Salome HOME
Merge from V6_main (04/10/2012)
[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 // File      : SMESH_MeshEditor.cxx
24 // Created   : Mon Apr 12 16:10:22 2004
25 // Author    : Edward AGAPOV (eap)
26
27 #include "SMESH_MeshEditor.hxx"
28
29 #include "SMDS_FaceOfNodes.hxx"
30 #include "SMDS_VolumeTool.hxx"
31 #include "SMDS_EdgePosition.hxx"
32 #include "SMDS_FacePosition.hxx"
33 #include "SMDS_SpacePosition.hxx"
34 #include "SMDS_MeshGroup.hxx"
35 #include "SMDS_LinearEdge.hxx"
36 #include "SMDS_Downward.hxx"
37 #include "SMDS_SetIterator.hxx"
38
39 #include "SMESHDS_Group.hxx"
40 #include "SMESHDS_Mesh.hxx"
41
42 #include "SMESH_Algo.hxx"
43 #include "SMESH_ControlsDef.hxx"
44 #include "SMESH_Group.hxx"
45 #include "SMESH_MesherHelper.hxx"
46 #include "SMESH_OctreeNode.hxx"
47 #include "SMESH_subMesh.hxx"
48
49 #include <Basics_OCCTVersion.hxx>
50
51 #include "utilities.h"
52
53 #include <BRepAdaptor_Surface.hxx>
54 #include <BRepBuilderAPI_MakeEdge.hxx>
55 #include <BRepClass3d_SolidClassifier.hxx>
56 #include <BRep_Tool.hxx>
57 #include <ElCLib.hxx>
58 #include <Extrema_GenExtPS.hxx>
59 #include <Extrema_POnCurv.hxx>
60 #include <Extrema_POnSurf.hxx>
61 #include <GC_MakeSegment.hxx>
62 #include <Geom2d_Curve.hxx>
63 #include <GeomAPI_ExtremaCurveCurve.hxx>
64 #include <GeomAdaptor_Surface.hxx>
65 #include <Geom_Curve.hxx>
66 #include <Geom_Line.hxx>
67 #include <Geom_Surface.hxx>
68 #include <IntAna_IntConicQuad.hxx>
69 #include <IntAna_Quadric.hxx>
70 #include <Precision.hxx>
71 #include <TColStd_ListOfInteger.hxx>
72 #include <TopAbs_State.hxx>
73 #include <TopExp.hxx>
74 #include <TopExp_Explorer.hxx>
75 #include <TopTools_ListIteratorOfListOfShape.hxx>
76 #include <TopTools_ListOfShape.hxx>
77 #include <TopTools_SequenceOfShape.hxx>
78 #include <TopoDS.hxx>
79 #include <TopoDS_Face.hxx>
80 #include <TopoDS_Solid.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                              const double                         ballDiameter)
135 {
136   //MESSAGE("AddElement " <<node.size() << " " << type << " " << isPoly << " " << ID);
137   SMDS_MeshElement* e = 0;
138   int nbnode = node.size();
139   SMESHDS_Mesh* mesh = GetMeshDS();
140   switch ( type ) {
141   case SMDSAbs_Face:
142     if ( !isPoly ) {
143       if      (nbnode == 3) {
144         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], ID);
145         else           e = mesh->AddFace      (node[0], node[1], node[2] );
146       }
147       else if (nbnode == 4) {
148         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3], ID);
149         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3] );
150       }
151       else if (nbnode == 6) {
152         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
153                                                node[4], node[5], ID);
154         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3],
155                                                node[4], node[5] );
156       }
157       else if (nbnode == 8) {
158         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
159                                                node[4], node[5], node[6], node[7], ID);
160         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3],
161                                                node[4], node[5], node[6], node[7] );
162       }
163       else if (nbnode == 9) {
164         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
165                                                node[4], node[5], node[6], node[7], node[8], ID);
166         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3],
167                                                node[4], node[5], node[6], node[7], node[8] );
168       }
169     } else {
170       if ( ID >= 1 ) e = mesh->AddPolygonalFaceWithID(node, ID);
171       else           e = mesh->AddPolygonalFace      (node    );
172     }
173     break;
174
175   case SMDSAbs_Volume:
176     if ( !isPoly ) {
177       if      (nbnode == 4) {
178         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], ID);
179         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3] );
180       }
181       else if (nbnode == 5) {
182         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
183                                                  node[4], ID);
184         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
185                                                  node[4] );
186       }
187       else if (nbnode == 6) {
188         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
189                                                  node[4], node[5], ID);
190         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
191                                                  node[4], node[5] );
192       }
193       else if (nbnode == 8) {
194         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
195                                                  node[4], node[5], node[6], node[7], ID);
196         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
197                                                  node[4], node[5], node[6], node[7] );
198       }
199       else if (nbnode == 10) {
200         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
201                                                  node[4], node[5], node[6], node[7],
202                                                  node[8], node[9], ID);
203         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
204                                                  node[4], node[5], node[6], node[7],
205                                                  node[8], node[9] );
206       }
207       else if (nbnode == 12) {
208         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
209                                                  node[4], node[5], node[6], node[7],
210                                                  node[8], node[9], node[10], node[11], ID);
211         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
212                                                  node[4], node[5], node[6], node[7],
213                                                  node[8], node[9], node[10], node[11] );
214       }
215       else if (nbnode == 13) {
216         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
217                                                  node[4], node[5], node[6], node[7],
218                                                  node[8], node[9], node[10],node[11],
219                                                  node[12],ID);
220         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
221                                                  node[4], node[5], node[6], node[7],
222                                                  node[8], node[9], node[10],node[11],
223                                                  node[12] );
224       }
225       else if (nbnode == 15) {
226         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
227                                                  node[4], node[5], node[6], node[7],
228                                                  node[8], node[9], node[10],node[11],
229                                                  node[12],node[13],node[14],ID);
230         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
231                                                  node[4], node[5], node[6], node[7],
232                                                  node[8], node[9], node[10],node[11],
233                                                  node[12],node[13],node[14] );
234       }
235       else if (nbnode == 20) {
236         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
237                                                  node[4], node[5], node[6], node[7],
238                                                  node[8], node[9], node[10],node[11],
239                                                  node[12],node[13],node[14],node[15],
240                                                  node[16],node[17],node[18],node[19],ID);
241         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
242                                                  node[4], node[5], node[6], node[7],
243                                                  node[8], node[9], node[10],node[11],
244                                                  node[12],node[13],node[14],node[15],
245                                                  node[16],node[17],node[18],node[19] );
246       }
247       else if (nbnode == 27) {
248         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
249                                                  node[4], node[5], node[6], node[7],
250                                                  node[8], node[9], node[10],node[11],
251                                                  node[12],node[13],node[14],node[15],
252                                                  node[16],node[17],node[18],node[19],
253                                                  node[20],node[21],node[22],node[23],
254                                                  node[24],node[25],node[26], ID);
255         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
256                                                  node[4], node[5], node[6], node[7],
257                                                  node[8], node[9], node[10],node[11],
258                                                  node[12],node[13],node[14],node[15],
259                                                  node[16],node[17],node[18],node[19],
260                                                  node[20],node[21],node[22],node[23],
261                                                  node[24],node[25],node[26] );
262       }
263     }
264     break;
265
266   case SMDSAbs_Edge:
267     if ( nbnode == 2 ) {
268       if ( ID >= 1 ) e = mesh->AddEdgeWithID(node[0], node[1], ID);
269       else           e = mesh->AddEdge      (node[0], node[1] );
270     }
271     else if ( nbnode == 3 ) {
272       if ( ID >= 1 ) e = mesh->AddEdgeWithID(node[0], node[1], node[2], ID);
273       else           e = mesh->AddEdge      (node[0], node[1], node[2] );
274     }
275     break;
276
277   case SMDSAbs_0DElement:
278     if ( nbnode == 1 ) {
279       if ( ID >= 1 ) e = mesh->Add0DElementWithID(node[0], ID);
280       else           e = mesh->Add0DElement      (node[0] );
281     }
282     break;
283
284   case SMDSAbs_Node:
285     if ( ID >= 1 ) e = mesh->AddNodeWithID(node[0]->X(), node[0]->Y(), node[0]->Z(), ID);
286     else           e = mesh->AddNode      (node[0]->X(), node[0]->Y(), node[0]->Z());
287     break;
288
289   case SMDSAbs_Ball:
290     if ( ID >= 1 ) e = mesh->AddBallWithID(node[0], ballDiameter, ID);
291     else           e = mesh->AddBall      (node[0], ballDiameter);
292     break;
293
294   default:;
295   }
296   if ( e ) myLastCreatedElems.Append( e );
297   return e;
298 }
299
300 //=======================================================================
301 /*!
302  * \brief Add element
303  */
304 //=======================================================================
305
306 SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector<int> &       nodeIDs,
307                                                const SMDSAbs_ElementType type,
308                                                const bool                isPoly,
309                                                const int                 ID)
310 {
311   vector<const SMDS_MeshNode*> nodes;
312   nodes.reserve( nodeIDs.size() );
313   vector<int>::const_iterator id = nodeIDs.begin();
314   while ( id != nodeIDs.end() ) {
315     if ( const SMDS_MeshNode* node = GetMeshDS()->FindNode( *id++ ))
316       nodes.push_back( node );
317     else
318       return 0;
319   }
320   return AddElement( nodes, type, isPoly, ID );
321 }
322
323 //=======================================================================
324 //function : Remove
325 //purpose  : Remove a node or an element.
326 //           Modify a compute state of sub-meshes which become empty
327 //=======================================================================
328
329 int SMESH_MeshEditor::Remove (const list< int >& theIDs,
330                               const bool         isNodes )
331 {
332   myLastCreatedElems.Clear();
333   myLastCreatedNodes.Clear();
334
335   SMESHDS_Mesh* aMesh = GetMeshDS();
336   set< SMESH_subMesh *> smmap;
337
338   int removed = 0;
339   list<int>::const_iterator it = theIDs.begin();
340   for ( ; it != theIDs.end(); it++ ) {
341     const SMDS_MeshElement * elem;
342     if ( isNodes )
343       elem = aMesh->FindNode( *it );
344     else
345       elem = aMesh->FindElement( *it );
346     if ( !elem )
347       continue;
348
349     // Notify VERTEX sub-meshes about modification
350     if ( isNodes ) {
351       const SMDS_MeshNode* node = cast2Node( elem );
352       if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX )
353         if ( int aShapeID = node->getshapeId() )
354           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
355             smmap.insert( sm );
356     }
357     // Find sub-meshes to notify about modification
358     //     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
359     //     while ( nodeIt->more() ) {
360     //       const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
361     //       const SMDS_PositionPtr& aPosition = node->GetPosition();
362     //       if ( aPosition.get() ) {
363     //         if ( int aShapeID = aPosition->GetShapeId() ) {
364     //           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
365     //             smmap.insert( sm );
366     //         }
367     //       }
368     //     }
369
370     // Do remove
371     if ( isNodes )
372       aMesh->RemoveNode( static_cast< const SMDS_MeshNode* >( elem ));
373     else
374       aMesh->RemoveElement( elem );
375     removed++;
376   }
377
378   // Notify sub-meshes about modification
379   if ( !smmap.empty() ) {
380     set< SMESH_subMesh *>::iterator smIt;
381     for ( smIt = smmap.begin(); smIt != smmap.end(); smIt++ )
382       (*smIt)->ComputeStateEngine( SMESH_subMesh::MESH_ENTITY_REMOVED );
383   }
384
385   //   // Check if the whole mesh becomes empty
386   //   if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( 1 ) )
387   //     sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
388
389   return removed;
390 }
391
392 //=======================================================================
393 //function : FindShape
394 //purpose  : Return an index of the shape theElem is on
395 //           or zero if a shape not found
396 //=======================================================================
397
398 int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem)
399 {
400   myLastCreatedElems.Clear();
401   myLastCreatedNodes.Clear();
402
403   SMESHDS_Mesh * aMesh = GetMeshDS();
404   if ( aMesh->ShapeToMesh().IsNull() )
405     return 0;
406
407   int aShapeID = theElem->getshapeId();
408   if ( aShapeID < 1 )
409     return 0;
410
411   if ( SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID ))
412     if ( sm->Contains( theElem ))
413       return aShapeID;
414
415   if ( theElem->GetType() == SMDSAbs_Node ) {
416     MESSAGE( ":( Error: invalid myShapeId of node " << theElem->GetID() );
417   }
418   else {
419     MESSAGE( ":( Error: invalid myShapeId of element " << theElem->GetID() );
420   }
421
422   TopoDS_Shape aShape; // the shape a node of theElem is on
423   if ( theElem->GetType() != SMDSAbs_Node )
424   {
425     SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
426     while ( nodeIt->more() ) {
427       const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
428       if ((aShapeID = node->getshapeId()) > 0) {
429         if ( SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID ) ) {
430           if ( sm->Contains( theElem ))
431             return aShapeID;
432           if ( aShape.IsNull() )
433             aShape = aMesh->IndexToShape( aShapeID );
434         }
435       }
436     }
437   }
438
439   // None of nodes is on a proper shape,
440   // find the shape among ancestors of aShape on which a node is
441   if ( !aShape.IsNull() ) {
442     TopTools_ListIteratorOfListOfShape ancIt( GetMesh()->GetAncestors( aShape ));
443     for ( ; ancIt.More(); ancIt.Next() ) {
444       SMESHDS_SubMesh * sm = aMesh->MeshElements( ancIt.Value() );
445       if ( sm && sm->Contains( theElem ))
446         return aMesh->ShapeToIndex( ancIt.Value() );
447     }
448   }
449   else
450   {
451     const map<int,SMESHDS_SubMesh*>& id2sm = GetMeshDS()->SubMeshes();
452     map<int,SMESHDS_SubMesh*>::const_iterator id_sm = id2sm.begin();
453     for ( ; id_sm != id2sm.end(); ++id_sm )
454       if ( id_sm->second->Contains( theElem ))
455         return id_sm->first;
456   }
457
458   //MESSAGE ("::FindShape() - SHAPE NOT FOUND")
459   return 0;
460 }
461
462 //=======================================================================
463 //function : IsMedium
464 //purpose  :
465 //=======================================================================
466
467 bool SMESH_MeshEditor::IsMedium(const SMDS_MeshNode*      node,
468                                 const SMDSAbs_ElementType typeToCheck)
469 {
470   bool isMedium = false;
471   SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(typeToCheck);
472   while (it->more() && !isMedium ) {
473     const SMDS_MeshElement* elem = it->next();
474     isMedium = elem->IsMediumNode(node);
475   }
476   return isMedium;
477 }
478
479 //=======================================================================
480 //function : ShiftNodesQuadTria
481 //purpose  : auxilary
482 //           Shift nodes in the array corresponded to quadratic triangle
483 //           example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
484 //=======================================================================
485 static void ShiftNodesQuadTria(const SMDS_MeshNode* aNodes[])
486 {
487   const SMDS_MeshNode* nd1 = aNodes[0];
488   aNodes[0] = aNodes[1];
489   aNodes[1] = aNodes[2];
490   aNodes[2] = nd1;
491   const SMDS_MeshNode* nd2 = aNodes[3];
492   aNodes[3] = aNodes[4];
493   aNodes[4] = aNodes[5];
494   aNodes[5] = nd2;
495 }
496
497 //=======================================================================
498 //function : edgeConnectivity
499 //purpose  : auxilary
500 //           return number of the edges connected with the theNode.
501 //           if theEdges has connections with the other type of the
502 //           elements, return -1
503 //=======================================================================
504 static int nbEdgeConnectivity(const SMDS_MeshNode* theNode)
505 {
506   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator();
507   int nb=0;
508   while(elemIt->more()) {
509     elemIt->next();
510     nb++;
511   }
512   return nb;
513 }
514
515
516 //=======================================================================
517 //function : GetNodesFromTwoTria
518 //purpose  : auxilary
519 //           Shift nodes in the array corresponded to quadratic triangle
520 //           example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
521 //=======================================================================
522 static bool GetNodesFromTwoTria(const SMDS_MeshElement * theTria1,
523                                 const SMDS_MeshElement * theTria2,
524                                 const SMDS_MeshNode* N1[],
525                                 const SMDS_MeshNode* N2[])
526 {
527   SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
528   int i=0;
529   while(i<6) {
530     N1[i] = static_cast<const SMDS_MeshNode*>( it->next() );
531     i++;
532   }
533   if(it->more()) return false;
534   it = theTria2->nodesIterator();
535   i=0;
536   while(i<6) {
537     N2[i] = static_cast<const SMDS_MeshNode*>( it->next() );
538     i++;
539   }
540   if(it->more()) return false;
541
542   int sames[3] = {-1,-1,-1};
543   int nbsames = 0;
544   int j;
545   for(i=0; i<3; i++) {
546     for(j=0; j<3; j++) {
547       if(N1[i]==N2[j]) {
548         sames[i] = j;
549         nbsames++;
550         break;
551       }
552     }
553   }
554   if(nbsames!=2) return false;
555   if(sames[0]>-1) {
556     ShiftNodesQuadTria(N1);
557     if(sames[1]>-1) {
558       ShiftNodesQuadTria(N1);
559     }
560   }
561   i = sames[0] + sames[1] + sames[2];
562   for(; i<2; i++) {
563     ShiftNodesQuadTria(N2);
564   }
565   // now we receive following N1 and N2 (using numeration as above image)
566   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
567   // i.e. first nodes from both arrays determ new diagonal
568   return true;
569 }
570
571 //=======================================================================
572 //function : InverseDiag
573 //purpose  : Replace two neighbour triangles with ones built on the same 4 nodes
574 //           but having other common link.
575 //           Return False if args are improper
576 //=======================================================================
577
578 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1,
579                                     const SMDS_MeshElement * theTria2 )
580 {
581   MESSAGE("InverseDiag");
582   myLastCreatedElems.Clear();
583   myLastCreatedNodes.Clear();
584
585   if (!theTria1 || !theTria2)
586     return false;
587
588   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( theTria1 );
589   if (!F1) return false;
590   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( theTria2 );
591   if (!F2) return false;
592   if ((theTria1->GetEntityType() == SMDSEntity_Triangle) &&
593       (theTria2->GetEntityType() == SMDSEntity_Triangle)) {
594
595     //  1 +--+ A  theTria1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
596     //    | /|    theTria2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
597     //    |/ |                                         | \|
598     //  B +--+ 2                                     B +--+ 2
599
600     // put nodes in array and find out indices of the same ones
601     const SMDS_MeshNode* aNodes [6];
602     int sameInd [] = { 0, 0, 0, 0, 0, 0 };
603     int i = 0;
604     SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
605     while ( it->more() ) {
606       aNodes[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
607
608       if ( i > 2 ) // theTria2
609         // find same node of theTria1
610         for ( int j = 0; j < 3; j++ )
611           if ( aNodes[ i ] == aNodes[ j ]) {
612             sameInd[ j ] = i;
613             sameInd[ i ] = j;
614             break;
615           }
616       // next
617       i++;
618       if ( i == 3 ) {
619         if ( it->more() )
620           return false; // theTria1 is not a triangle
621         it = theTria2->nodesIterator();
622       }
623       if ( i == 6 && it->more() )
624         return false; // theTria2 is not a triangle
625     }
626
627     // find indices of 1,2 and of A,B in theTria1
628     int iA = 0, iB = 0, i1 = 0, i2 = 0;
629     for ( i = 0; i < 6; i++ ) {
630       if ( sameInd [ i ] == 0 ) {
631         if ( i < 3 ) i1 = i;
632         else         i2 = i;
633       }
634       else if (i < 3) {
635         if ( iA ) iB = i;
636         else      iA = i;
637       }
638     }
639     // nodes 1 and 2 should not be the same
640     if ( aNodes[ i1 ] == aNodes[ i2 ] )
641       return false;
642
643     // theTria1: A->2
644     aNodes[ iA ] = aNodes[ i2 ];
645     // theTria2: B->1
646     aNodes[ sameInd[ iB ]] = aNodes[ i1 ];
647
648     GetMeshDS()->ChangeElementNodes( theTria1, aNodes, 3 );
649     GetMeshDS()->ChangeElementNodes( theTria2, &aNodes[ 3 ], 3 );
650
651     return true;
652
653   } // end if(F1 && F2)
654
655   // check case of quadratic faces
656   if (theTria1->GetEntityType() != SMDSEntity_Quad_Triangle)
657     return false;
658   if (theTria2->GetEntityType() != SMDSEntity_Quad_Triangle)
659     return false;
660
661   //       5
662   //  1 +--+--+ 2  theTria1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
663   //    |    /|    theTria2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
664   //    |   / |
665   //  7 +  +  + 6
666   //    | /9  |
667   //    |/    |
668   //  4 +--+--+ 3
669   //       8
670
671   const SMDS_MeshNode* N1 [6];
672   const SMDS_MeshNode* N2 [6];
673   if(!GetNodesFromTwoTria(theTria1,theTria2,N1,N2))
674     return false;
675   // now we receive following N1 and N2 (using numeration as above image)
676   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
677   // i.e. first nodes from both arrays determ new diagonal
678
679   const SMDS_MeshNode* N1new [6];
680   const SMDS_MeshNode* N2new [6];
681   N1new[0] = N1[0];
682   N1new[1] = N2[0];
683   N1new[2] = N2[1];
684   N1new[3] = N1[4];
685   N1new[4] = N2[3];
686   N1new[5] = N1[5];
687   N2new[0] = N1[0];
688   N2new[1] = N1[1];
689   N2new[2] = N2[0];
690   N2new[3] = N1[3];
691   N2new[4] = N2[5];
692   N2new[5] = N1[4];
693   // replaces nodes in faces
694   GetMeshDS()->ChangeElementNodes( theTria1, N1new, 6 );
695   GetMeshDS()->ChangeElementNodes( theTria2, N2new, 6 );
696
697   return true;
698 }
699
700 //=======================================================================
701 //function : findTriangles
702 //purpose  : find triangles sharing theNode1-theNode2 link
703 //=======================================================================
704
705 static bool findTriangles(const SMDS_MeshNode *    theNode1,
706                           const SMDS_MeshNode *    theNode2,
707                           const SMDS_MeshElement*& theTria1,
708                           const SMDS_MeshElement*& theTria2)
709 {
710   if ( !theNode1 || !theNode2 ) return false;
711
712   theTria1 = theTria2 = 0;
713
714   set< const SMDS_MeshElement* > emap;
715   SMDS_ElemIteratorPtr it = theNode1->GetInverseElementIterator(SMDSAbs_Face);
716   while (it->more()) {
717     const SMDS_MeshElement* elem = it->next();
718     if ( elem->NbNodes() == 3 )
719       emap.insert( elem );
720   }
721   it = theNode2->GetInverseElementIterator(SMDSAbs_Face);
722   while (it->more()) {
723     const SMDS_MeshElement* elem = it->next();
724     if ( emap.find( elem ) != emap.end() ) {
725       if ( theTria1 ) {
726         // theTria1 must be element with minimum ID
727         if( theTria1->GetID() < elem->GetID() ) {
728           theTria2 = elem;
729         }
730         else {
731           theTria2 = theTria1;
732           theTria1 = elem;
733         }
734         break;
735       }
736       else {
737         theTria1 = elem;
738       }
739     }
740   }
741   return ( theTria1 && theTria2 );
742 }
743
744 //=======================================================================
745 //function : InverseDiag
746 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
747 //           with ones built on the same 4 nodes but having other common link.
748 //           Return false if proper faces not found
749 //=======================================================================
750
751 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshNode * theNode1,
752                                     const SMDS_MeshNode * theNode2)
753 {
754   myLastCreatedElems.Clear();
755   myLastCreatedNodes.Clear();
756
757   MESSAGE( "::InverseDiag()" );
758
759   const SMDS_MeshElement *tr1, *tr2;
760   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
761     return false;
762
763   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
764   if (!F1) return false;
765   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
766   if (!F2) return false;
767   if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
768       (tr2->GetEntityType() == SMDSEntity_Triangle)) {
769
770     //  1 +--+ A  tr1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
771     //    | /|    tr2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
772     //    |/ |                                    | \|
773     //  B +--+ 2                                B +--+ 2
774
775     // put nodes in array
776     // and find indices of 1,2 and of A in tr1 and of B in tr2
777     int i, iA1 = 0, i1 = 0;
778     const SMDS_MeshNode* aNodes1 [3];
779     SMDS_ElemIteratorPtr it;
780     for (i = 0, it = tr1->nodesIterator(); it->more(); i++ ) {
781       aNodes1[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
782       if ( aNodes1[ i ] == theNode1 )
783         iA1 = i; // node A in tr1
784       else if ( aNodes1[ i ] != theNode2 )
785         i1 = i;  // node 1
786     }
787     int iB2 = 0, i2 = 0;
788     const SMDS_MeshNode* aNodes2 [3];
789     for (i = 0, it = tr2->nodesIterator(); it->more(); i++ ) {
790       aNodes2[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
791       if ( aNodes2[ i ] == theNode2 )
792         iB2 = i; // node B in tr2
793       else if ( aNodes2[ i ] != theNode1 )
794         i2 = i;  // node 2
795     }
796
797     // nodes 1 and 2 should not be the same
798     if ( aNodes1[ i1 ] == aNodes2[ i2 ] )
799       return false;
800
801     // tr1: A->2
802     aNodes1[ iA1 ] = aNodes2[ i2 ];
803     // tr2: B->1
804     aNodes2[ iB2 ] = aNodes1[ i1 ];
805
806     GetMeshDS()->ChangeElementNodes( tr1, aNodes1, 3 );
807     GetMeshDS()->ChangeElementNodes( tr2, aNodes2, 3 );
808
809     return true;
810   }
811
812   // check case of quadratic faces
813   return InverseDiag(tr1,tr2);
814 }
815
816 //=======================================================================
817 //function : getQuadrangleNodes
818 //purpose  : fill theQuadNodes - nodes of a quadrangle resulting from
819 //           fusion of triangles tr1 and tr2 having shared link on
820 //           theNode1 and theNode2
821 //=======================================================================
822
823 bool getQuadrangleNodes(const SMDS_MeshNode *    theQuadNodes [],
824                         const SMDS_MeshNode *    theNode1,
825                         const SMDS_MeshNode *    theNode2,
826                         const SMDS_MeshElement * tr1,
827                         const SMDS_MeshElement * tr2 )
828 {
829   if( tr1->NbNodes() != tr2->NbNodes() )
830     return false;
831   // find the 4-th node to insert into tr1
832   const SMDS_MeshNode* n4 = 0;
833   SMDS_ElemIteratorPtr it = tr2->nodesIterator();
834   int i=0;
835   while ( !n4 && i<3 ) {
836     const SMDS_MeshNode * n = cast2Node( it->next() );
837     i++;
838     bool isDiag = ( n == theNode1 || n == theNode2 );
839     if ( !isDiag )
840       n4 = n;
841   }
842   // Make an array of nodes to be in a quadrangle
843   int iNode = 0, iFirstDiag = -1;
844   it = tr1->nodesIterator();
845   i=0;
846   while ( i<3 ) {
847     const SMDS_MeshNode * n = cast2Node( it->next() );
848     i++;
849     bool isDiag = ( n == theNode1 || n == theNode2 );
850     if ( isDiag ) {
851       if ( iFirstDiag < 0 )
852         iFirstDiag = iNode;
853       else if ( iNode - iFirstDiag == 1 )
854         theQuadNodes[ iNode++ ] = n4; // insert the 4-th node between diagonal nodes
855     }
856     else if ( n == n4 ) {
857       return false; // tr1 and tr2 should not have all the same nodes
858     }
859     theQuadNodes[ iNode++ ] = n;
860   }
861   if ( iNode == 3 ) // diagonal nodes have 0 and 2 indices
862     theQuadNodes[ iNode ] = n4;
863
864   return true;
865 }
866
867 //=======================================================================
868 //function : DeleteDiag
869 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
870 //           with a quadrangle built on the same 4 nodes.
871 //           Return false if proper faces not found
872 //=======================================================================
873
874 bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1,
875                                    const SMDS_MeshNode * theNode2)
876 {
877   myLastCreatedElems.Clear();
878   myLastCreatedNodes.Clear();
879
880   MESSAGE( "::DeleteDiag()" );
881
882   const SMDS_MeshElement *tr1, *tr2;
883   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
884     return false;
885
886   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
887   if (!F1) return false;
888   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
889   if (!F2) return false;
890   SMESHDS_Mesh * aMesh = GetMeshDS();
891
892   if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
893       (tr2->GetEntityType() == SMDSEntity_Triangle)) {
894
895     const SMDS_MeshNode* aNodes [ 4 ];
896     if ( ! getQuadrangleNodes( aNodes, theNode1, theNode2, tr1, tr2 ))
897       return false;
898
899     const SMDS_MeshElement* newElem = 0;
900     newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3] );
901     myLastCreatedElems.Append(newElem);
902     AddToSameGroups( newElem, tr1, aMesh );
903     int aShapeId = tr1->getshapeId();
904     if ( aShapeId )
905       {
906         aMesh->SetMeshElementOnShape( newElem, aShapeId );
907       }
908     aMesh->RemoveElement( tr1 );
909     aMesh->RemoveElement( tr2 );
910
911     return true;
912   }
913
914   // check case of quadratic faces
915   if (tr1->GetEntityType() != SMDSEntity_Quad_Triangle)
916     return false;
917   if (tr2->GetEntityType() != SMDSEntity_Quad_Triangle)
918     return false;
919
920   //       5
921   //  1 +--+--+ 2  tr1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
922   //    |    /|    tr2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
923   //    |   / |
924   //  7 +  +  + 6
925   //    | /9  |
926   //    |/    |
927   //  4 +--+--+ 3
928   //       8
929
930   const SMDS_MeshNode* N1 [6];
931   const SMDS_MeshNode* N2 [6];
932   if(!GetNodesFromTwoTria(tr1,tr2,N1,N2))
933     return false;
934   // now we receive following N1 and N2 (using numeration as above image)
935   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
936   // i.e. first nodes from both arrays determ new diagonal
937
938   const SMDS_MeshNode* aNodes[8];
939   aNodes[0] = N1[0];
940   aNodes[1] = N1[1];
941   aNodes[2] = N2[0];
942   aNodes[3] = N2[1];
943   aNodes[4] = N1[3];
944   aNodes[5] = N2[5];
945   aNodes[6] = N2[3];
946   aNodes[7] = N1[5];
947
948   const SMDS_MeshElement* newElem = 0;
949   newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3],
950                             aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
951   myLastCreatedElems.Append(newElem);
952   AddToSameGroups( newElem, tr1, aMesh );
953   int aShapeId = tr1->getshapeId();
954   if ( aShapeId )
955     {
956       aMesh->SetMeshElementOnShape( newElem, aShapeId );
957     }
958   aMesh->RemoveElement( tr1 );
959   aMesh->RemoveElement( tr2 );
960
961   // remove middle node (9)
962   GetMeshDS()->RemoveNode( N1[4] );
963
964   return true;
965 }
966
967 //=======================================================================
968 //function : Reorient
969 //purpose  : Reverse theElement orientation
970 //=======================================================================
971
972 bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem)
973 {
974   MESSAGE("Reorient");
975   myLastCreatedElems.Clear();
976   myLastCreatedNodes.Clear();
977
978   if (!theElem)
979     return false;
980   SMDS_ElemIteratorPtr it = theElem->nodesIterator();
981   if ( !it || !it->more() )
982     return false;
983
984   switch ( theElem->GetType() ) {
985
986   case SMDSAbs_Edge:
987   case SMDSAbs_Face: {
988     if(!theElem->IsQuadratic()) {
989       int i = theElem->NbNodes();
990       vector<const SMDS_MeshNode*> aNodes( i );
991       while ( it->more() )
992         aNodes[ --i ]= static_cast<const SMDS_MeshNode*>( it->next() );
993       return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], theElem->NbNodes() );
994     }
995     else {
996       // quadratic elements
997       if(theElem->GetType()==SMDSAbs_Edge) {
998         vector<const SMDS_MeshNode*> aNodes(3);
999         aNodes[1]= static_cast<const SMDS_MeshNode*>( it->next() );
1000         aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
1001         aNodes[2]= static_cast<const SMDS_MeshNode*>( it->next() );
1002         return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], 3 );
1003       }
1004       else {
1005         int nbn = theElem->NbNodes();
1006         vector<const SMDS_MeshNode*> aNodes(nbn);
1007         aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
1008         int i=1;
1009         for(; i<nbn/2; i++) {
1010           aNodes[nbn/2-i]= static_cast<const SMDS_MeshNode*>( it->next() );
1011         }
1012         for(i=0; i<nbn/2; i++) {
1013           aNodes[nbn-i-1]= static_cast<const SMDS_MeshNode*>( it->next() );
1014         }
1015         return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], nbn );
1016       }
1017     }
1018   }
1019   case SMDSAbs_Volume: {
1020     if (theElem->IsPoly()) {
1021       // TODO reorient vtk polyhedron
1022       MESSAGE("reorient vtk polyhedron ?");
1023       const SMDS_VtkVolume* aPolyedre =
1024         dynamic_cast<const SMDS_VtkVolume*>( theElem );
1025       if (!aPolyedre) {
1026         MESSAGE("Warning: bad volumic element");
1027         return false;
1028       }
1029
1030       int nbFaces = aPolyedre->NbFaces();
1031       vector<const SMDS_MeshNode *> poly_nodes;
1032       vector<int> quantities (nbFaces);
1033
1034       // reverse each face of the polyedre
1035       for (int iface = 1; iface <= nbFaces; iface++) {
1036         int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
1037         quantities[iface - 1] = nbFaceNodes;
1038
1039         for (inode = nbFaceNodes; inode >= 1; inode--) {
1040           const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
1041           poly_nodes.push_back(curNode);
1042         }
1043       }
1044
1045       return GetMeshDS()->ChangePolyhedronNodes( theElem, poly_nodes, quantities );
1046
1047     }
1048     else {
1049       SMDS_VolumeTool vTool;
1050       if ( !vTool.Set( theElem ))
1051         return false;
1052       vTool.Inverse();
1053       MESSAGE("ChangeElementNodes reorient: check vTool.Inverse");
1054       return GetMeshDS()->ChangeElementNodes( theElem, vTool.GetNodes(), vTool.NbNodes() );
1055     }
1056   }
1057   default:;
1058   }
1059
1060   return false;
1061 }
1062
1063 //================================================================================
1064 /*!
1065  * \brief Reorient faces.
1066  * \param theFaces - the faces to reorient. If empty the whole mesh is meant
1067  * \param theDirection - desired direction of normal of \a theFace
1068  * \param theFace - one of \a theFaces that sould be orientated according to
1069  *        \a theDirection and whose orientation defines orientation of other faces
1070  * \return number of reoriented faces.
1071  */
1072 //================================================================================
1073
1074 int SMESH_MeshEditor::Reorient2D (TIDSortedElemSet &       theFaces,
1075                                   const gp_Dir&            theDirection,
1076                                   const SMDS_MeshElement * theFace)
1077 {
1078   int nbReori = 0;
1079   if ( !theFace || theFace->GetType() != SMDSAbs_Face ) return nbReori;
1080
1081   if ( theFaces.empty() )
1082   {
1083     SMDS_FaceIteratorPtr fIt = GetMeshDS()->facesIterator(/*idInceasingOrder=*/true);
1084     while ( fIt->more() )
1085       theFaces.insert( theFaces.end(), fIt->next() );
1086   }
1087
1088   // orient theFace according to theDirection
1089   gp_XYZ normal;
1090   SMESH_Algo::FaceNormal( theFace, normal, /*normalized=*/false );
1091   if ( normal * theDirection.XYZ() < 0 )
1092     nbReori += Reorient( theFace );
1093
1094   // Orient other faces
1095
1096   set< const SMDS_MeshElement* > startFaces;
1097   TIDSortedElemSet avoidSet;
1098   set< SMESH_TLink > checkedLinks;
1099   pair< set< SMESH_TLink >::iterator, bool > linkIt_isNew;
1100
1101   if ( theFaces.size() > 1 )// leave 1 face to prevent finding not selected faces
1102     theFaces.erase( theFace );
1103   startFaces.insert( theFace );
1104
1105   set< const SMDS_MeshElement* >::iterator startFace = startFaces.begin();
1106   while ( startFace != startFaces.end() )
1107   {
1108     theFace = *startFace;
1109     const int nbNodes = theFace->NbCornerNodes();
1110
1111     avoidSet.clear();
1112     avoidSet.insert(theFace);
1113
1114     NLink link( theFace->GetNode( 0 ), 0 );
1115     for ( int i = 0; i < nbNodes; ++i ) // loop on links of theFace
1116     {
1117       link.second = theFace->GetNode(( i+1 ) % nbNodes );
1118       linkIt_isNew = checkedLinks.insert( link );
1119       if ( !linkIt_isNew.second )
1120       {
1121         // link has already been checked and won't be encountered more
1122         // if the group (theFaces) is manifold
1123         checkedLinks.erase( linkIt_isNew.first );
1124       }
1125       else
1126       {
1127         int nodeInd1, nodeInd2;
1128         const SMDS_MeshElement* otherFace = FindFaceInSet( link.first, link.second,
1129                                                            theFaces, avoidSet,
1130                                                            & nodeInd1, & nodeInd2);
1131         if ( otherFace && otherFace != theFace)
1132         {
1133           // link must be reversed in otherFace if orientation ot otherFace
1134           // is same as that of theFace
1135           if ( abs(nodeInd2-nodeInd1) == 1 ? nodeInd2 > nodeInd1 : nodeInd1 > nodeInd2 )
1136           {
1137             // cout << "Reorient " << otherFace->GetID() << " near theFace=" <<theFace->GetID()
1138             //      << " \tlink( " << link.first->GetID() << " " << link.second->GetID() << endl;
1139             nbReori += Reorient( otherFace );
1140           }
1141           startFaces.insert( otherFace );
1142           if ( theFaces.size() > 1 ) // leave 1 face to prevent finding not selected faces
1143             theFaces.erase( otherFace );
1144         }
1145       }
1146       std::swap( link.first, link.second );
1147     }
1148     startFaces.erase( startFace );
1149     startFace = startFaces.begin();
1150   }
1151   return nbReori;
1152 }
1153
1154 //=======================================================================
1155 //function : getBadRate
1156 //purpose  :
1157 //=======================================================================
1158
1159 static double getBadRate (const SMDS_MeshElement*               theElem,
1160                           SMESH::Controls::NumericalFunctorPtr& theCrit)
1161 {
1162   SMESH::Controls::TSequenceOfXYZ P;
1163   if ( !theElem || !theCrit->GetPoints( theElem, P ))
1164     return 1e100;
1165   return theCrit->GetBadRate( theCrit->GetValue( P ), theElem->NbNodes() );
1166   //return theCrit->GetBadRate( theCrit->GetValue( theElem->GetID() ), theElem->NbNodes() );
1167 }
1168
1169 //=======================================================================
1170 //function : QuadToTri
1171 //purpose  : Cut quadrangles into triangles.
1172 //           theCrit is used to select a diagonal to cut
1173 //=======================================================================
1174
1175 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet &                   theElems,
1176                                   SMESH::Controls::NumericalFunctorPtr theCrit)
1177 {
1178   myLastCreatedElems.Clear();
1179   myLastCreatedNodes.Clear();
1180
1181   MESSAGE( "::QuadToTri()" );
1182
1183   if ( !theCrit.get() )
1184     return false;
1185
1186   SMESHDS_Mesh * aMesh = GetMeshDS();
1187
1188   Handle(Geom_Surface) surface;
1189   SMESH_MesherHelper   helper( *GetMesh() );
1190
1191   TIDSortedElemSet::iterator itElem;
1192   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1193     const SMDS_MeshElement* elem = *itElem;
1194     if ( !elem || elem->GetType() != SMDSAbs_Face )
1195       continue;
1196     if ( elem->NbCornerNodes() != 4 )
1197       continue;
1198
1199     // retrieve element nodes
1200     vector< const SMDS_MeshNode* > aNodes( elem->begin_nodes(), elem->end_nodes() );
1201
1202     // compare two sets of possible triangles
1203     double aBadRate1, aBadRate2; // to what extent a set is bad
1204     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1205     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1206     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1207
1208     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1209     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1210     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1211
1212     int aShapeId = FindShape( elem );
1213     const SMDS_MeshElement* newElem1 = 0;
1214     const SMDS_MeshElement* newElem2 = 0;
1215
1216     if( !elem->IsQuadratic() ) {
1217
1218       // split liner quadrangle
1219
1220       if ( aBadRate1 <= aBadRate2 ) {
1221         // tr1 + tr2 is better
1222         newElem1 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1223         newElem2 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
1224       }
1225       else {
1226         // tr3 + tr4 is better
1227         newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1228         newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
1229       }
1230     }
1231     else {
1232
1233       // split quadratic quadrangle
1234
1235       // get surface elem is on
1236       if ( aShapeId != helper.GetSubShapeID() ) {
1237         surface.Nullify();
1238         TopoDS_Shape shape;
1239         if ( aShapeId > 0 )
1240           shape = aMesh->IndexToShape( aShapeId );
1241         if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1242           TopoDS_Face face = TopoDS::Face( shape );
1243           surface = BRep_Tool::Surface( face );
1244           if ( !surface.IsNull() )
1245             helper.SetSubShape( shape );
1246         }
1247       }
1248       // find middle point for (0,1,2,3)
1249       // and create a node in this point;
1250       const SMDS_MeshNode* newN = 0;
1251       if ( aNodes.size() == 9 )
1252       {
1253         // SMDSEntity_BiQuad_Quadrangle
1254         newN = aNodes.back();
1255       }
1256       else
1257       {
1258         gp_XYZ p( 0,0,0 );
1259         if ( surface.IsNull() )
1260         {
1261           for ( int i = 0; i < 4; i++ )
1262             p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1263           p /= 4;
1264         }
1265         else
1266         {
1267           const SMDS_MeshNode* inFaceNode = 0;
1268           if ( helper.GetNodeUVneedInFaceNode() )
1269             for ( size_t i = 0; i < aNodes.size() && !inFaceNode; ++i )
1270               if ( aNodes[ i ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1271                 inFaceNode = aNodes[ i ];
1272
1273           TopoDS_Face face = TopoDS::Face( helper.GetSubShape() );
1274           gp_XY uv( 0,0 );
1275           for ( int i = 0; i < 4; i++ )
1276             uv += helper.GetNodeUV( face, aNodes[i], inFaceNode );
1277           uv /= 4.;
1278           p = surface->Value( uv.X(), uv.Y() ).XYZ();
1279         }
1280         newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1281         myLastCreatedNodes.Append(newN);
1282       }
1283       // create a new element
1284       if ( aBadRate1 <= aBadRate2 ) {
1285         newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1286                                   aNodes[6], aNodes[7], newN );
1287         newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
1288                                   newN,      aNodes[4], aNodes[5] );
1289       }
1290       else {
1291         newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1292                                   aNodes[7], aNodes[4], newN );
1293         newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
1294                                   newN,      aNodes[5], aNodes[6] );
1295       }
1296     } // quadratic case
1297
1298     // care of a new element
1299
1300     myLastCreatedElems.Append(newElem1);
1301     myLastCreatedElems.Append(newElem2);
1302     AddToSameGroups( newElem1, elem, aMesh );
1303     AddToSameGroups( newElem2, elem, aMesh );
1304
1305     // put a new triangle on the same shape
1306     if ( aShapeId )
1307       {
1308         aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1309         aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1310       }
1311     aMesh->RemoveElement( elem );
1312   }
1313   return true;
1314 }
1315
1316 //=======================================================================
1317 //function : BestSplit
1318 //purpose  : Find better diagonal for cutting.
1319 //=======================================================================
1320
1321 int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement*              theQuad,
1322                                  SMESH::Controls::NumericalFunctorPtr theCrit)
1323 {
1324   myLastCreatedElems.Clear();
1325   myLastCreatedNodes.Clear();
1326
1327   if (!theCrit.get())
1328     return -1;
1329
1330   if (!theQuad || theQuad->GetType() != SMDSAbs_Face )
1331     return -1;
1332
1333   if( theQuad->NbNodes()==4 ||
1334       (theQuad->NbNodes()==8 && theQuad->IsQuadratic()) ) {
1335
1336     // retrieve element nodes
1337     const SMDS_MeshNode* aNodes [4];
1338     SMDS_ElemIteratorPtr itN = theQuad->nodesIterator();
1339     int i = 0;
1340     //while (itN->more())
1341     while (i<4) {
1342       aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1343     }
1344     // compare two sets of possible triangles
1345     double aBadRate1, aBadRate2; // to what extent a set is bad
1346     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1347     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1348     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1349
1350     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1351     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1352     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1353
1354     if (aBadRate1 <= aBadRate2) // tr1 + tr2 is better
1355       return 1; // diagonal 1-3
1356
1357     return 2; // diagonal 2-4
1358   }
1359   return -1;
1360 }
1361
1362 namespace
1363 {
1364   // Methods of splitting volumes into tetra
1365
1366   const int theHexTo5_1[5*4+1] =
1367     {
1368       0, 1, 2, 5,    0, 4, 5, 7,     0, 2, 3, 7,    2, 5, 6, 7,     0, 5, 2, 7,   -1
1369     };
1370   const int theHexTo5_2[5*4+1] =
1371     {
1372       1, 2, 3, 6,    1, 4, 5, 6,     0, 1, 3, 4,    3, 4, 6, 7,     1, 3, 4, 6,   -1
1373     };
1374   const int* theHexTo5[2] = { theHexTo5_1, theHexTo5_2 };
1375
1376   const int theHexTo6_1[6*4+1] =
1377     {
1378       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
1379     };
1380   const int theHexTo6_2[6*4+1] =
1381     {
1382       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
1383     };
1384   const int theHexTo6_3[6*4+1] =
1385     {
1386       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
1387     };
1388   const int theHexTo6_4[6*4+1] =
1389     {
1390       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
1391     };
1392   const int* theHexTo6[4] = { theHexTo6_1, theHexTo6_2, theHexTo6_3, theHexTo6_4 };
1393
1394   const int thePyraTo2_1[2*4+1] =
1395     {
1396       0, 1, 2, 4,    0, 2, 3, 4,   -1
1397     };
1398   const int thePyraTo2_2[2*4+1] =
1399     {
1400       1, 2, 3, 4,    1, 3, 0, 4,   -1
1401     };
1402   const int* thePyraTo2[2] = { thePyraTo2_1, thePyraTo2_2 };
1403
1404   const int thePentaTo3_1[3*4+1] =
1405     {
1406       0, 1, 2, 3,    1, 3, 4, 2,     2, 3, 4, 5,    -1
1407     };
1408   const int thePentaTo3_2[3*4+1] =
1409     {
1410       1, 2, 0, 4,    2, 4, 5, 0,     0, 4, 5, 3,    -1
1411     };
1412   const int thePentaTo3_3[3*4+1] =
1413     {
1414       2, 0, 1, 5,    0, 5, 3, 1,     1, 5, 3, 4,    -1
1415     };
1416   const int thePentaTo3_4[3*4+1] =
1417     {
1418       0, 1, 2, 3,    1, 3, 4, 5,     2, 3, 1, 5,    -1
1419     };
1420   const int thePentaTo3_5[3*4+1] =
1421     {
1422       1, 2, 0, 4,    2, 4, 5, 3,     0, 4, 2, 3,    -1
1423     };
1424   const int thePentaTo3_6[3*4+1] =
1425     {
1426       2, 0, 1, 5,    0, 5, 3, 4,     1, 5, 0, 4,    -1
1427     };
1428   const int* thePentaTo3[6] = { thePentaTo3_1, thePentaTo3_2, thePentaTo3_3,
1429                                 thePentaTo3_4, thePentaTo3_5, thePentaTo3_6 };
1430
1431   struct TTriangleFacet //!< stores indices of three nodes of tetra facet
1432   {
1433     int _n1, _n2, _n3;
1434     TTriangleFacet(int n1, int n2, int n3): _n1(n1), _n2(n2), _n3(n3) {}
1435     bool contains(int n) const { return ( n == _n1 || n == _n2 || n == _n3 ); }
1436     bool hasAdjacentTetra( const SMDS_MeshElement* elem ) const;
1437   };
1438   struct TSplitMethod
1439   {
1440     int        _nbTetra;
1441     const int* _connectivity; //!< foursomes of tetra connectivy finished by -1
1442     bool       _baryNode;     //!< additional node is to be created at cell barycenter
1443     bool       _ownConn;      //!< to delete _connectivity in destructor
1444     map<int, const SMDS_MeshNode*> _faceBaryNode; //!< map face index to node at BC of face
1445
1446     TSplitMethod( int nbTet=0, const int* conn=0, bool addNode=false)
1447       : _nbTetra(nbTet), _connectivity(conn), _baryNode(addNode), _ownConn(false) {}
1448     ~TSplitMethod() { if ( _ownConn ) delete [] _connectivity; _connectivity = 0; }
1449     bool hasFacet( const TTriangleFacet& facet ) const
1450     {
1451       const int* tetConn = _connectivity;
1452       for ( ; tetConn[0] >= 0; tetConn += 4 )
1453         if (( facet.contains( tetConn[0] ) +
1454               facet.contains( tetConn[1] ) +
1455               facet.contains( tetConn[2] ) +
1456               facet.contains( tetConn[3] )) == 3 )
1457           return true;
1458       return false;
1459     }
1460   };
1461
1462   //=======================================================================
1463   /*!
1464    * \brief return TSplitMethod for the given element
1465    */
1466   //=======================================================================
1467
1468   TSplitMethod getSplitMethod( SMDS_VolumeTool& vol, const int theMethodFlags)
1469   {
1470     const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1471
1472     // at HEXA_TO_24 method, each face of volume is split into triangles each based on
1473     // an edge and a face barycenter; tertaherdons are based on triangles and
1474     // a volume barycenter
1475     const bool is24TetMode = ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_24 );
1476
1477     // Find out how adjacent volumes are split
1478
1479     vector < list< TTriangleFacet > > triaSplitsByFace( vol.NbFaces() ); // splits of each side
1480     int hasAdjacentSplits = 0, maxTetConnSize = 0;
1481     for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1482     {
1483       int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1484       maxTetConnSize += 4 * ( nbNodes - (is24TetMode ? 0 : 2));
1485       if ( nbNodes < 4 ) continue;
1486
1487       list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1488       const int* nInd = vol.GetFaceNodesIndices( iF );
1489       if ( nbNodes == 4 )
1490       {
1491         TTriangleFacet t012( nInd[0*iQ], nInd[1*iQ], nInd[2*iQ] );
1492         TTriangleFacet t123( nInd[1*iQ], nInd[2*iQ], nInd[3*iQ] );
1493         if      ( t012.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t012 );
1494         else if ( t123.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t123 );
1495       }
1496       else
1497       {
1498         int iCom = 0; // common node of triangle faces to split into
1499         for ( int iVar = 0; iVar < nbNodes; ++iVar, ++iCom )
1500         {
1501           TTriangleFacet t012( nInd[ iQ * ( iCom             )],
1502                                nInd[ iQ * ( (iCom+1)%nbNodes )],
1503                                nInd[ iQ * ( (iCom+2)%nbNodes )]);
1504           TTriangleFacet t023( nInd[ iQ * ( iCom             )],
1505                                nInd[ iQ * ( (iCom+2)%nbNodes )],
1506                                nInd[ iQ * ( (iCom+3)%nbNodes )]);
1507           if ( t012.hasAdjacentTetra( vol.Element() ) && t023.hasAdjacentTetra( vol.Element() ))
1508           {
1509             triaSplits.push_back( t012 );
1510             triaSplits.push_back( t023 );
1511             break;
1512           }
1513         }
1514       }
1515       if ( !triaSplits.empty() )
1516         hasAdjacentSplits = true;
1517     }
1518
1519     // Among variants of split method select one compliant with adjacent volumes
1520
1521     TSplitMethod method;
1522     if ( !vol.Element()->IsPoly() && !is24TetMode )
1523     {
1524       int nbVariants = 2, nbTet = 0;
1525       const int** connVariants = 0;
1526       switch ( vol.Element()->GetEntityType() )
1527       {
1528       case SMDSEntity_Hexa:
1529       case SMDSEntity_Quad_Hexa:
1530       case SMDSEntity_TriQuad_Hexa:
1531         if ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_5 )
1532           connVariants = theHexTo5, nbTet = 5;
1533         else
1534           connVariants = theHexTo6, nbTet = 6, nbVariants = 4;
1535         break;
1536       case SMDSEntity_Pyramid:
1537       case SMDSEntity_Quad_Pyramid:
1538         connVariants = thePyraTo2;  nbTet = 2;
1539         break;
1540       case SMDSEntity_Penta:
1541       case SMDSEntity_Quad_Penta:
1542         connVariants = thePentaTo3; nbTet = 3; nbVariants = 6;
1543         break;
1544       default:
1545         nbVariants = 0;
1546       }
1547       for ( int variant = 0; variant < nbVariants && method._nbTetra == 0; ++variant )
1548       {
1549         // check method compliancy with adjacent tetras,
1550         // all found splits must be among facets of tetras described by this method
1551         method = TSplitMethod( nbTet, connVariants[variant] );
1552         if ( hasAdjacentSplits && method._nbTetra > 0 )
1553         {
1554           bool facetCreated = true;
1555           for ( int iF = 0; facetCreated && iF < triaSplitsByFace.size(); ++iF )
1556           {
1557             list< TTriangleFacet >::const_iterator facet = triaSplitsByFace[iF].begin();
1558             for ( ; facetCreated && facet != triaSplitsByFace[iF].end(); ++facet )
1559               facetCreated = method.hasFacet( *facet );
1560           }
1561           if ( !facetCreated )
1562             method = TSplitMethod(0); // incompatible method
1563         }
1564       }
1565     }
1566     if ( method._nbTetra < 1 )
1567     {
1568       // No standard method is applicable, use a generic solution:
1569       // each facet of a volume is split into triangles and
1570       // each of triangles and a volume barycenter form a tetrahedron.
1571
1572       const bool isHex27 = ( vol.Element()->GetEntityType() == SMDSEntity_TriQuad_Hexa );
1573
1574       int* connectivity = new int[ maxTetConnSize + 1 ];
1575       method._connectivity = connectivity;
1576       method._ownConn = true;
1577       method._baryNode = !isHex27; // to create central node or not
1578
1579       int connSize = 0;
1580       int baryCenInd = vol.NbNodes() - int( isHex27 );
1581       for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1582       {
1583         const int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1584         const int*   nInd = vol.GetFaceNodesIndices( iF );
1585         // find common node of triangle facets of tetra to create
1586         int iCommon = 0; // index in linear numeration
1587         const list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1588         if ( !triaSplits.empty() )
1589         {
1590           // by found facets
1591           const TTriangleFacet* facet = &triaSplits.front();
1592           for ( ; iCommon < nbNodes-1 ; ++iCommon )
1593             if ( facet->contains( nInd[ iQ * iCommon ]) &&
1594                  facet->contains( nInd[ iQ * ((iCommon+2)%nbNodes) ]))
1595               break;
1596         }
1597         else if ( nbNodes > 3 && !is24TetMode )
1598         {
1599           // find the best method of splitting into triangles by aspect ratio
1600           SMESH::Controls::NumericalFunctorPtr aspectRatio( new SMESH::Controls::AspectRatio);
1601           map< double, int > badness2iCommon;
1602           const SMDS_MeshNode** nodes = vol.GetFaceNodes( iF );
1603           int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1604           for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCommon )
1605           {
1606             double badness = 0;
1607             for ( int iLast = iCommon+2; iLast < iCommon+nbNodes; ++iLast )
1608             {
1609               SMDS_FaceOfNodes tria ( nodes[ iQ*( iCommon         )],
1610                                       nodes[ iQ*((iLast-1)%nbNodes)],
1611                                       nodes[ iQ*((iLast  )%nbNodes)]);
1612               badness += getBadRate( &tria, aspectRatio );
1613             }
1614             badness2iCommon.insert( make_pair( badness, iCommon ));
1615           }
1616           // use iCommon with lowest badness
1617           iCommon = badness2iCommon.begin()->second;
1618         }
1619         if ( iCommon >= nbNodes )
1620           iCommon = 0; // something wrong
1621
1622         // fill connectivity of tetrahedra based on a current face
1623         int nbTet = nbNodes - 2;
1624         if ( is24TetMode && nbNodes > 3 && triaSplits.empty())
1625         {
1626           int faceBaryCenInd;
1627           if ( isHex27 )
1628           {
1629             faceBaryCenInd = vol.GetCenterNodeIndex( iF );
1630             method._faceBaryNode[ iF ] = vol.GetNodes()[ faceBaryCenInd ];
1631           }
1632           else
1633           {
1634             method._faceBaryNode[ iF ] = 0;
1635             faceBaryCenInd = baryCenInd + method._faceBaryNode.size();
1636           }
1637           nbTet = nbNodes;
1638           for ( int i = 0; i < nbTet; ++i )
1639           {
1640             int i1 = i, i2 = (i+1) % nbNodes;
1641             if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1642             connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1643             connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1644             connectivity[ connSize++ ] = faceBaryCenInd;
1645             connectivity[ connSize++ ] = baryCenInd;
1646           }
1647         }
1648         else
1649         {
1650           for ( int i = 0; i < nbTet; ++i )
1651           {
1652             int i1 = (iCommon+1+i) % nbNodes, i2 = (iCommon+2+i) % nbNodes;
1653             if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1654             connectivity[ connSize++ ] = nInd[ iQ * iCommon ];
1655             connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1656             connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1657             connectivity[ connSize++ ] = baryCenInd;
1658           }
1659         }
1660         method._nbTetra += nbTet;
1661
1662       } // loop on volume faces
1663
1664       connectivity[ connSize++ ] = -1;
1665
1666     } // end of generic solution
1667
1668     return method;
1669   }
1670   //================================================================================
1671   /*!
1672    * \brief Check if there is a tetraherdon adjacent to the given element via this facet
1673    */
1674   //================================================================================
1675
1676   bool TTriangleFacet::hasAdjacentTetra( const SMDS_MeshElement* elem ) const
1677   {
1678     // find the tetrahedron including the three nodes of facet
1679     const SMDS_MeshNode* n1 = elem->GetNode(_n1);
1680     const SMDS_MeshNode* n2 = elem->GetNode(_n2);
1681     const SMDS_MeshNode* n3 = elem->GetNode(_n3);
1682     SMDS_ElemIteratorPtr volIt1 = n1->GetInverseElementIterator(SMDSAbs_Volume);
1683     while ( volIt1->more() )
1684     {
1685       const SMDS_MeshElement* v = volIt1->next();
1686       SMDSAbs_EntityType type = v->GetEntityType();
1687       if ( type != SMDSEntity_Tetra && type != SMDSEntity_Quad_Tetra )
1688         continue;
1689       if ( type == SMDSEntity_Quad_Tetra && v->GetNodeIndex( n1 ) > 3 )
1690         continue; // medium node not allowed
1691       const int ind2 = v->GetNodeIndex( n2 );
1692       if ( ind2 < 0 || 3 < ind2 )
1693         continue;
1694       const int ind3 = v->GetNodeIndex( n3 );
1695       if ( ind3 < 0 || 3 < ind3 )
1696         continue;
1697       return true;
1698     }
1699     return false;
1700   }
1701
1702   //=======================================================================
1703   /*!
1704    * \brief A key of a face of volume
1705    */
1706   //=======================================================================
1707
1708   struct TVolumeFaceKey: pair< pair< int, int>, pair< int, int> >
1709   {
1710     TVolumeFaceKey( SMDS_VolumeTool& vol, int iF )
1711     {
1712       TIDSortedNodeSet sortedNodes;
1713       const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1714       int nbNodes = vol.NbFaceNodes( iF );
1715       const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iF );
1716       for ( int i = 0; i < nbNodes; i += iQ )
1717         sortedNodes.insert( fNodes[i] );
1718       TIDSortedNodeSet::iterator n = sortedNodes.begin();
1719       first.first   = (*(n++))->GetID();
1720       first.second  = (*(n++))->GetID();
1721       second.first  = (*(n++))->GetID();
1722       second.second = ( sortedNodes.size() > 3 ) ? (*(n++))->GetID() : 0;
1723     }
1724   };
1725 } // namespace
1726
1727 //=======================================================================
1728 //function : SplitVolumesIntoTetra
1729 //purpose  : Split volume elements into tetrahedra.
1730 //=======================================================================
1731
1732 void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
1733                                               const int                theMethodFlags)
1734 {
1735   // std-like iterator on coordinates of nodes of mesh element
1736   typedef SMDS_StdIterator< SMESH_TNodeXYZ, SMDS_ElemIteratorPtr > NXyzIterator;
1737   NXyzIterator xyzEnd;
1738
1739   SMDS_VolumeTool    volTool;
1740   SMESH_MesherHelper helper( *GetMesh());
1741
1742   SMESHDS_SubMesh* subMesh = 0;//GetMeshDS()->MeshElements(1);
1743   SMESHDS_SubMesh* fSubMesh = 0;//subMesh;
1744
1745   SMESH_SequenceOfElemPtr newNodes, newElems;
1746
1747   // map face of volume to it's baricenrtic node
1748   map< TVolumeFaceKey, const SMDS_MeshNode* > volFace2BaryNode;
1749   double bc[3];
1750
1751   TIDSortedElemSet::const_iterator elem = theElems.begin();
1752   for ( ; elem != theElems.end(); ++elem )
1753   {
1754     if ( (*elem)->GetType() != SMDSAbs_Volume )
1755       continue;
1756     SMDSAbs_EntityType geomType = (*elem)->GetEntityType();
1757     if ( geomType == SMDSEntity_Tetra || geomType == SMDSEntity_Quad_Tetra )
1758       continue;
1759
1760     if ( !volTool.Set( *elem, /*ignoreCentralNodes=*/false )) continue; // strange...
1761
1762     TSplitMethod splitMethod = getSplitMethod( volTool, theMethodFlags );
1763     if ( splitMethod._nbTetra < 1 ) continue;
1764
1765     // find submesh to add new tetras to
1766     if ( !subMesh || !subMesh->Contains( *elem ))
1767     {
1768       int shapeID = FindShape( *elem );
1769       helper.SetSubShape( shapeID ); // helper will add tetras to the found submesh
1770       subMesh = GetMeshDS()->MeshElements( shapeID );
1771     }
1772     int iQ;
1773     if ( (*elem)->IsQuadratic() )
1774     {
1775       iQ = 2;
1776       // add quadratic links to the helper
1777       for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1778       {
1779         const SMDS_MeshNode** fNodes = volTool.GetFaceNodes( iF );
1780         int nbN = volTool.NbFaceNodes( iF ) - bool( volTool.GetCenterNodeIndex(iF) > 0 );
1781         for ( int iN = 0; iN < nbN; iN += iQ )
1782           helper.AddTLinkNode( fNodes[iN], fNodes[iN+2], fNodes[iN+1] );
1783       }
1784       helper.SetIsQuadratic( true );
1785     }
1786     else
1787     {
1788       iQ = 1;
1789       helper.SetIsQuadratic( false );
1790     }
1791     vector<const SMDS_MeshNode*> nodes( (*elem)->begin_nodes(), (*elem)->end_nodes() );
1792     helper.SetElementsOnShape( true );
1793     if ( splitMethod._baryNode )
1794     {
1795       // make a node at barycenter
1796       volTool.GetBaryCenter( bc[0], bc[1], bc[2] );
1797       SMDS_MeshNode* gcNode = helper.AddNode( bc[0], bc[1], bc[2] );
1798       nodes.push_back( gcNode );
1799       newNodes.Append( gcNode );
1800     }
1801     if ( !splitMethod._faceBaryNode.empty() )
1802     {
1803       // make or find baricentric nodes of faces
1804       map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.begin();
1805       for ( ; iF_n != splitMethod._faceBaryNode.end(); ++iF_n )
1806       {
1807         map< TVolumeFaceKey, const SMDS_MeshNode* >::iterator f_n =
1808           volFace2BaryNode.insert
1809           ( make_pair( TVolumeFaceKey( volTool,iF_n->first ), iF_n->second )).first;
1810         if ( !f_n->second )
1811         {
1812           volTool.GetFaceBaryCenter( iF_n->first, bc[0], bc[1], bc[2] );
1813           newNodes.Append( f_n->second = helper.AddNode( bc[0], bc[1], bc[2] ));
1814         }
1815         nodes.push_back( iF_n->second = f_n->second );
1816       }
1817     }
1818
1819     // make tetras
1820     vector<const SMDS_MeshElement* > tetras( splitMethod._nbTetra ); // splits of a volume
1821     const int* tetConn = splitMethod._connectivity;
1822     for ( int i = 0; i < splitMethod._nbTetra; ++i, tetConn += 4 )
1823       newElems.Append( tetras[ i ] = helper.AddVolume( nodes[ tetConn[0] ],
1824                                                        nodes[ tetConn[1] ],
1825                                                        nodes[ tetConn[2] ],
1826                                                        nodes[ tetConn[3] ]));
1827
1828     ReplaceElemInGroups( *elem, tetras, GetMeshDS() );
1829
1830     // Split faces on sides of the split volume
1831
1832     const SMDS_MeshNode** volNodes = volTool.GetNodes();
1833     for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1834     {
1835       const int nbNodes = volTool.NbFaceNodes( iF ) / iQ;
1836       if ( nbNodes < 4 ) continue;
1837
1838       // find an existing face
1839       vector<const SMDS_MeshNode*> fNodes( volTool.GetFaceNodes( iF ),
1840                                            volTool.GetFaceNodes( iF ) + volTool.NbFaceNodes( iF ));
1841       while ( const SMDS_MeshElement* face = GetMeshDS()->FindElement( fNodes, SMDSAbs_Face,
1842                                                                        /*noMedium=*/false))
1843       {
1844         // make triangles
1845         helper.SetElementsOnShape( false );
1846         vector< const SMDS_MeshElement* > triangles;
1847
1848         // find submesh to add new triangles in
1849         if ( !fSubMesh || !fSubMesh->Contains( face ))
1850         {
1851           int shapeID = FindShape( face );
1852           fSubMesh = GetMeshDS()->MeshElements( shapeID );
1853         }
1854         map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.find(iF);
1855         if ( iF_n != splitMethod._faceBaryNode.end() )
1856         {
1857           for ( int iN = 0; iN < nbNodes*iQ; iN += iQ )
1858           {
1859             const SMDS_MeshNode* n1 = fNodes[iN];
1860             const SMDS_MeshNode *n2 = fNodes[(iN+iQ)%(nbNodes*iQ)];
1861             const SMDS_MeshNode *n3 = iF_n->second;
1862             if ( !volTool.IsFaceExternal( iF ))
1863               swap( n2, n3 );
1864             triangles.push_back( helper.AddFace( n1,n2,n3 ));
1865
1866             if ( fSubMesh && n3->getshapeId() < 1 )
1867               fSubMesh->AddNode( n3 );
1868           }
1869         }
1870         else
1871         {
1872           // among possible triangles create ones discribed by split method
1873           const int* nInd = volTool.GetFaceNodesIndices( iF );
1874           int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1875           int iCom = 0; // common node of triangle faces to split into
1876           list< TTriangleFacet > facets;
1877           for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCom )
1878           {
1879             TTriangleFacet t012( nInd[ iQ * ( iCom                )],
1880                                  nInd[ iQ * ( (iCom+1)%nbNodes )],
1881                                  nInd[ iQ * ( (iCom+2)%nbNodes )]);
1882             TTriangleFacet t023( nInd[ iQ * ( iCom                )],
1883                                  nInd[ iQ * ( (iCom+2)%nbNodes )],
1884                                  nInd[ iQ * ( (iCom+3)%nbNodes )]);
1885             if ( splitMethod.hasFacet( t012 ) && splitMethod.hasFacet( t023 ))
1886             {
1887               facets.push_back( t012 );
1888               facets.push_back( t023 );
1889               for ( int iLast = iCom+4; iLast < iCom+nbNodes; ++iLast )
1890                 facets.push_back( TTriangleFacet( nInd[ iQ * ( iCom             )],
1891                                                   nInd[ iQ * ((iLast-1)%nbNodes )],
1892                                                   nInd[ iQ * ((iLast  )%nbNodes )]));
1893               break;
1894             }
1895           }
1896           list< TTriangleFacet >::iterator facet = facets.begin();
1897           for ( ; facet != facets.end(); ++facet )
1898           {
1899             if ( !volTool.IsFaceExternal( iF ))
1900               swap( facet->_n2, facet->_n3 );
1901             triangles.push_back( helper.AddFace( volNodes[ facet->_n1 ],
1902                                                  volNodes[ facet->_n2 ],
1903                                                  volNodes[ facet->_n3 ]));
1904           }
1905         }
1906         for ( int i = 0; i < triangles.size(); ++i )
1907         {
1908           if ( !triangles[i] ) continue;
1909           if ( fSubMesh )
1910             fSubMesh->AddElement( triangles[i]);
1911           newElems.Append( triangles[i] );
1912         }
1913         ReplaceElemInGroups( face, triangles, GetMeshDS() );
1914         GetMeshDS()->RemoveFreeElement( face, fSubMesh, /*fromGroups=*/false );
1915       }
1916
1917     } // loop on volume faces to split them into triangles
1918
1919     GetMeshDS()->RemoveFreeElement( *elem, subMesh, /*fromGroups=*/false );
1920
1921     if ( geomType == SMDSEntity_TriQuad_Hexa )
1922     {
1923       // remove medium nodes that could become free
1924       for ( int i = 20; i < volTool.NbNodes(); ++i )
1925         if ( volNodes[i]->NbInverseElements() == 0 )
1926           GetMeshDS()->RemoveNode( volNodes[i] );
1927     }
1928   } // loop on volumes to split
1929
1930   myLastCreatedNodes = newNodes;
1931   myLastCreatedElems = newElems;
1932 }
1933
1934 //=======================================================================
1935 //function : AddToSameGroups
1936 //purpose  : add elemToAdd to the groups the elemInGroups belongs to
1937 //=======================================================================
1938
1939 void SMESH_MeshEditor::AddToSameGroups (const SMDS_MeshElement* elemToAdd,
1940                                         const SMDS_MeshElement* elemInGroups,
1941                                         SMESHDS_Mesh *          aMesh)
1942 {
1943   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1944   if (!groups.empty()) {
1945     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1946     for ( ; grIt != groups.end(); grIt++ ) {
1947       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1948       if ( group && group->Contains( elemInGroups ))
1949         group->SMDSGroup().Add( elemToAdd );
1950     }
1951   }
1952 }
1953
1954
1955 //=======================================================================
1956 //function : RemoveElemFromGroups
1957 //purpose  : Remove removeelem to the groups the elemInGroups belongs to
1958 //=======================================================================
1959 void SMESH_MeshEditor::RemoveElemFromGroups (const SMDS_MeshElement* removeelem,
1960                                              SMESHDS_Mesh *          aMesh)
1961 {
1962   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1963   if (!groups.empty())
1964   {
1965     set<SMESHDS_GroupBase*>::const_iterator GrIt = groups.begin();
1966     for (; GrIt != groups.end(); GrIt++)
1967     {
1968       SMESHDS_Group* grp = dynamic_cast<SMESHDS_Group*>(*GrIt);
1969       if (!grp || grp->IsEmpty()) continue;
1970       grp->SMDSGroup().Remove(removeelem);
1971     }
1972   }
1973 }
1974
1975 //================================================================================
1976 /*!
1977  * \brief Replace elemToRm by elemToAdd in the all groups
1978  */
1979 //================================================================================
1980
1981 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
1982                                             const SMDS_MeshElement* elemToAdd,
1983                                             SMESHDS_Mesh *          aMesh)
1984 {
1985   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1986   if (!groups.empty()) {
1987     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1988     for ( ; grIt != groups.end(); grIt++ ) {
1989       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1990       if ( group && group->SMDSGroup().Remove( elemToRm ) && elemToAdd )
1991         group->SMDSGroup().Add( elemToAdd );
1992     }
1993   }
1994 }
1995
1996 //================================================================================
1997 /*!
1998  * \brief Replace elemToRm by elemToAdd in the all groups
1999  */
2000 //================================================================================
2001
2002 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement*                elemToRm,
2003                                             const vector<const SMDS_MeshElement*>& elemToAdd,
2004                                             SMESHDS_Mesh *                         aMesh)
2005 {
2006   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
2007   if (!groups.empty())
2008   {
2009     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
2010     for ( ; grIt != groups.end(); grIt++ ) {
2011       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
2012       if ( group && group->SMDSGroup().Remove( elemToRm ) )
2013         for ( int i = 0; i < elemToAdd.size(); ++i )
2014           group->SMDSGroup().Add( elemToAdd[ i ] );
2015     }
2016   }
2017 }
2018
2019 //=======================================================================
2020 //function : QuadToTri
2021 //purpose  : Cut quadrangles into triangles.
2022 //           theCrit is used to select a diagonal to cut
2023 //=======================================================================
2024
2025 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
2026                                   const bool         the13Diag)
2027 {
2028   myLastCreatedElems.Clear();
2029   myLastCreatedNodes.Clear();
2030
2031   MESSAGE( "::QuadToTri()" );
2032
2033   SMESHDS_Mesh * aMesh = GetMeshDS();
2034
2035   Handle(Geom_Surface) surface;
2036   SMESH_MesherHelper   helper( *GetMesh() );
2037
2038   TIDSortedElemSet::iterator itElem;
2039   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2040     const SMDS_MeshElement* elem = *itElem;
2041     if ( !elem || elem->GetType() != SMDSAbs_Face )
2042       continue;
2043     bool isquad = elem->NbNodes()==4 || elem->NbNodes()==8;
2044     if(!isquad) continue;
2045
2046     if(elem->NbNodes()==4) {
2047       // retrieve element nodes
2048       const SMDS_MeshNode* aNodes [4];
2049       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2050       int i = 0;
2051       while ( itN->more() )
2052         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
2053
2054       int aShapeId = FindShape( elem );
2055       const SMDS_MeshElement* newElem1 = 0;
2056       const SMDS_MeshElement* newElem2 = 0;
2057       if ( the13Diag ) {
2058         newElem1 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
2059         newElem2 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
2060       }
2061       else {
2062         newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
2063         newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
2064       }
2065       myLastCreatedElems.Append(newElem1);
2066       myLastCreatedElems.Append(newElem2);
2067       // put a new triangle on the same shape and add to the same groups
2068       if ( aShapeId )
2069         {
2070           aMesh->SetMeshElementOnShape( newElem1, aShapeId );
2071           aMesh->SetMeshElementOnShape( newElem2, aShapeId );
2072         }
2073       AddToSameGroups( newElem1, elem, aMesh );
2074       AddToSameGroups( newElem2, elem, aMesh );
2075       //aMesh->RemoveFreeElement(elem, aMesh->MeshElements(aShapeId), true);
2076       aMesh->RemoveElement( elem );
2077     }
2078
2079     // Quadratic quadrangle
2080
2081     if( elem->NbNodes()==8 && elem->IsQuadratic() ) {
2082
2083       // get surface elem is on
2084       int aShapeId = FindShape( elem );
2085       if ( aShapeId != helper.GetSubShapeID() ) {
2086         surface.Nullify();
2087         TopoDS_Shape shape;
2088         if ( aShapeId > 0 )
2089           shape = aMesh->IndexToShape( aShapeId );
2090         if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
2091           TopoDS_Face face = TopoDS::Face( shape );
2092           surface = BRep_Tool::Surface( face );
2093           if ( !surface.IsNull() )
2094             helper.SetSubShape( shape );
2095         }
2096       }
2097
2098       const SMDS_MeshNode* aNodes [8];
2099       const SMDS_MeshNode* inFaceNode = 0;
2100       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2101       int i = 0;
2102       while ( itN->more() ) {
2103         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
2104         if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
2105              aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
2106         {
2107           inFaceNode = aNodes[ i-1 ];
2108         }
2109       }
2110
2111       // find middle point for (0,1,2,3)
2112       // and create a node in this point;
2113       gp_XYZ p( 0,0,0 );
2114       if ( surface.IsNull() ) {
2115         for(i=0; i<4; i++)
2116           p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
2117         p /= 4;
2118       }
2119       else {
2120         TopoDS_Face geomFace = TopoDS::Face( helper.GetSubShape() );
2121         gp_XY uv( 0,0 );
2122         for(i=0; i<4; i++)
2123           uv += helper.GetNodeUV( geomFace, aNodes[i], inFaceNode );
2124         uv /= 4.;
2125         p = surface->Value( uv.X(), uv.Y() ).XYZ();
2126       }
2127       const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
2128       myLastCreatedNodes.Append(newN);
2129
2130       // create a new element
2131       const SMDS_MeshElement* newElem1 = 0;
2132       const SMDS_MeshElement* newElem2 = 0;
2133       if ( the13Diag ) {
2134         newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
2135                                   aNodes[6], aNodes[7], newN );
2136         newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
2137                                   newN,      aNodes[4], aNodes[5] );
2138       }
2139       else {
2140         newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
2141                                   aNodes[7], aNodes[4], newN );
2142         newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
2143                                   newN,      aNodes[5], aNodes[6] );
2144       }
2145       myLastCreatedElems.Append(newElem1);
2146       myLastCreatedElems.Append(newElem2);
2147       // put a new triangle on the same shape and add to the same groups
2148       if ( aShapeId )
2149         {
2150           aMesh->SetMeshElementOnShape( newElem1, aShapeId );
2151           aMesh->SetMeshElementOnShape( newElem2, aShapeId );
2152         }
2153       AddToSameGroups( newElem1, elem, aMesh );
2154       AddToSameGroups( newElem2, elem, aMesh );
2155       aMesh->RemoveElement( elem );
2156     }
2157   }
2158
2159   return true;
2160 }
2161
2162 //=======================================================================
2163 //function : getAngle
2164 //purpose  :
2165 //=======================================================================
2166
2167 double getAngle(const SMDS_MeshElement * tr1,
2168                 const SMDS_MeshElement * tr2,
2169                 const SMDS_MeshNode *    n1,
2170                 const SMDS_MeshNode *    n2)
2171 {
2172   double angle = 2. * M_PI; // bad angle
2173
2174   // get normals
2175   SMESH::Controls::TSequenceOfXYZ P1, P2;
2176   if ( !SMESH::Controls::NumericalFunctor::GetPoints( tr1, P1 ) ||
2177        !SMESH::Controls::NumericalFunctor::GetPoints( tr2, P2 ))
2178     return angle;
2179   gp_Vec N1,N2;
2180   if(!tr1->IsQuadratic())
2181     N1 = gp_Vec( P1(2) - P1(1) ) ^ gp_Vec( P1(3) - P1(1) );
2182   else
2183     N1 = gp_Vec( P1(3) - P1(1) ) ^ gp_Vec( P1(5) - P1(1) );
2184   if ( N1.SquareMagnitude() <= gp::Resolution() )
2185     return angle;
2186   if(!tr2->IsQuadratic())
2187     N2 = gp_Vec( P2(2) - P2(1) ) ^ gp_Vec( P2(3) - P2(1) );
2188   else
2189     N2 = gp_Vec( P2(3) - P2(1) ) ^ gp_Vec( P2(5) - P2(1) );
2190   if ( N2.SquareMagnitude() <= gp::Resolution() )
2191     return angle;
2192
2193   // find the first diagonal node n1 in the triangles:
2194   // take in account a diagonal link orientation
2195   const SMDS_MeshElement *nFirst[2], *tr[] = { tr1, tr2 };
2196   for ( int t = 0; t < 2; t++ ) {
2197     SMDS_ElemIteratorPtr it = tr[ t ]->nodesIterator();
2198     int i = 0, iDiag = -1;
2199     while ( it->more()) {
2200       const SMDS_MeshElement *n = it->next();
2201       if ( n == n1 || n == n2 ) {
2202         if ( iDiag < 0)
2203           iDiag = i;
2204         else {
2205           if ( i - iDiag == 1 )
2206             nFirst[ t ] = ( n == n1 ? n2 : n1 );
2207           else
2208             nFirst[ t ] = n;
2209           break;
2210         }
2211       }
2212       i++;
2213     }
2214   }
2215   if ( nFirst[ 0 ] == nFirst[ 1 ] )
2216     N2.Reverse();
2217
2218   angle = N1.Angle( N2 );
2219   //SCRUTE( angle );
2220   return angle;
2221 }
2222
2223 // =================================================
2224 // class generating a unique ID for a pair of nodes
2225 // and able to return nodes by that ID
2226 // =================================================
2227 class LinkID_Gen {
2228 public:
2229
2230   LinkID_Gen( const SMESHDS_Mesh* theMesh )
2231     :myMesh( theMesh ), myMaxID( theMesh->MaxNodeID() + 1)
2232   {}
2233
2234   long GetLinkID (const SMDS_MeshNode * n1,
2235                   const SMDS_MeshNode * n2) const
2236   {
2237     return ( Min(n1->GetID(),n2->GetID()) * myMaxID + Max(n1->GetID(),n2->GetID()));
2238   }
2239
2240   bool GetNodes (const long             theLinkID,
2241                  const SMDS_MeshNode* & theNode1,
2242                  const SMDS_MeshNode* & theNode2) const
2243   {
2244     theNode1 = myMesh->FindNode( theLinkID / myMaxID );
2245     if ( !theNode1 ) return false;
2246     theNode2 = myMesh->FindNode( theLinkID % myMaxID );
2247     if ( !theNode2 ) return false;
2248     return true;
2249   }
2250
2251 private:
2252   LinkID_Gen();
2253   const SMESHDS_Mesh* myMesh;
2254   long                myMaxID;
2255 };
2256
2257
2258 //=======================================================================
2259 //function : TriToQuad
2260 //purpose  : Fuse neighbour triangles into quadrangles.
2261 //           theCrit is used to select a neighbour to fuse with.
2262 //           theMaxAngle is a max angle between element normals at which
2263 //           fusion is still performed.
2264 //=======================================================================
2265
2266 bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet &                   theElems,
2267                                   SMESH::Controls::NumericalFunctorPtr theCrit,
2268                                   const double                         theMaxAngle)
2269 {
2270   myLastCreatedElems.Clear();
2271   myLastCreatedNodes.Clear();
2272
2273   MESSAGE( "::TriToQuad()" );
2274
2275   if ( !theCrit.get() )
2276     return false;
2277
2278   SMESHDS_Mesh * aMesh = GetMeshDS();
2279
2280   // Prepare data for algo: build
2281   // 1. map of elements with their linkIDs
2282   // 2. map of linkIDs with their elements
2283
2284   map< SMESH_TLink, list< const SMDS_MeshElement* > > mapLi_listEl;
2285   map< SMESH_TLink, list< const SMDS_MeshElement* > >::iterator itLE;
2286   map< const SMDS_MeshElement*, set< SMESH_TLink > >  mapEl_setLi;
2287   map< const SMDS_MeshElement*, set< SMESH_TLink > >::iterator itEL;
2288
2289   TIDSortedElemSet::iterator itElem;
2290   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2291     const SMDS_MeshElement* elem = *itElem;
2292     if(!elem || elem->GetType() != SMDSAbs_Face ) continue;
2293     bool IsTria = elem->NbNodes()==3 || (elem->NbNodes()==6 && elem->IsQuadratic());
2294     if(!IsTria) continue;
2295
2296     // retrieve element nodes
2297     const SMDS_MeshNode* aNodes [4];
2298     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2299     int i = 0;
2300     while ( i<3 )
2301       aNodes[ i++ ] = cast2Node( itN->next() );
2302     aNodes[ 3 ] = aNodes[ 0 ];
2303
2304     // fill maps
2305     for ( i = 0; i < 3; i++ ) {
2306       SMESH_TLink link( aNodes[i], aNodes[i+1] );
2307       // check if elements sharing a link can be fused
2308       itLE = mapLi_listEl.find( link );
2309       if ( itLE != mapLi_listEl.end() ) {
2310         if ((*itLE).second.size() > 1 ) // consider only 2 elems adjacent by a link
2311           continue;
2312         const SMDS_MeshElement* elem2 = (*itLE).second.front();
2313         //if ( FindShape( elem ) != FindShape( elem2 ))
2314         //  continue; // do not fuse triangles laying on different shapes
2315         if ( getAngle( elem, elem2, aNodes[i], aNodes[i+1] ) > theMaxAngle )
2316           continue; // avoid making badly shaped quads
2317         (*itLE).second.push_back( elem );
2318       }
2319       else {
2320         mapLi_listEl[ link ].push_back( elem );
2321       }
2322       mapEl_setLi [ elem ].insert( link );
2323     }
2324   }
2325   // Clean the maps from the links shared by a sole element, ie
2326   // links to which only one element is bound in mapLi_listEl
2327
2328   for ( itLE = mapLi_listEl.begin(); itLE != mapLi_listEl.end(); itLE++ ) {
2329     int nbElems = (*itLE).second.size();
2330     if ( nbElems < 2  ) {
2331       const SMDS_MeshElement* elem = (*itLE).second.front();
2332       SMESH_TLink link = (*itLE).first;
2333       mapEl_setLi[ elem ].erase( link );
2334       if ( mapEl_setLi[ elem ].empty() )
2335         mapEl_setLi.erase( elem );
2336     }
2337   }
2338
2339   // Algo: fuse triangles into quadrangles
2340
2341   while ( ! mapEl_setLi.empty() ) {
2342     // Look for the start element:
2343     // the element having the least nb of shared links
2344     const SMDS_MeshElement* startElem = 0;
2345     int minNbLinks = 4;
2346     for ( itEL = mapEl_setLi.begin(); itEL != mapEl_setLi.end(); itEL++ ) {
2347       int nbLinks = (*itEL).second.size();
2348       if ( nbLinks < minNbLinks ) {
2349         startElem = (*itEL).first;
2350         minNbLinks = nbLinks;
2351         if ( minNbLinks == 1 )
2352           break;
2353       }
2354     }
2355
2356     // search elements to fuse starting from startElem or links of elements
2357     // fused earlyer - startLinks
2358     list< SMESH_TLink > startLinks;
2359     while ( startElem || !startLinks.empty() ) {
2360       while ( !startElem && !startLinks.empty() ) {
2361         // Get an element to start, by a link
2362         SMESH_TLink linkId = startLinks.front();
2363         startLinks.pop_front();
2364         itLE = mapLi_listEl.find( linkId );
2365         if ( itLE != mapLi_listEl.end() ) {
2366           list< const SMDS_MeshElement* > & listElem = (*itLE).second;
2367           list< const SMDS_MeshElement* >::iterator itE = listElem.begin();
2368           for ( ; itE != listElem.end() ; itE++ )
2369             if ( mapEl_setLi.find( (*itE) ) != mapEl_setLi.end() )
2370               startElem = (*itE);
2371           mapLi_listEl.erase( itLE );
2372         }
2373       }
2374
2375       if ( startElem ) {
2376         // Get candidates to be fused
2377         const SMDS_MeshElement *tr1 = startElem, *tr2 = 0, *tr3 = 0;
2378         const SMESH_TLink *link12, *link13;
2379         startElem = 0;
2380         ASSERT( mapEl_setLi.find( tr1 ) != mapEl_setLi.end() );
2381         set< SMESH_TLink >& setLi = mapEl_setLi[ tr1 ];
2382         ASSERT( !setLi.empty() );
2383         set< SMESH_TLink >::iterator itLi;
2384         for ( itLi = setLi.begin(); itLi != setLi.end(); itLi++ )
2385         {
2386           const SMESH_TLink & link = (*itLi);
2387           itLE = mapLi_listEl.find( link );
2388           if ( itLE == mapLi_listEl.end() )
2389             continue;
2390
2391           const SMDS_MeshElement* elem = (*itLE).second.front();
2392           if ( elem == tr1 )
2393             elem = (*itLE).second.back();
2394           mapLi_listEl.erase( itLE );
2395           if ( mapEl_setLi.find( elem ) == mapEl_setLi.end())
2396             continue;
2397           if ( tr2 ) {
2398             tr3 = elem;
2399             link13 = &link;
2400           }
2401           else {
2402             tr2 = elem;
2403             link12 = &link;
2404           }
2405
2406           // add other links of elem to list of links to re-start from
2407           set< SMESH_TLink >& links = mapEl_setLi[ elem ];
2408           set< SMESH_TLink >::iterator it;
2409           for ( it = links.begin(); it != links.end(); it++ ) {
2410             const SMESH_TLink& link2 = (*it);
2411             if ( link2 != link )
2412               startLinks.push_back( link2 );
2413           }
2414         }
2415
2416         // Get nodes of possible quadrangles
2417         const SMDS_MeshNode *n12 [4], *n13 [4];
2418         bool Ok12 = false, Ok13 = false;
2419         const SMDS_MeshNode *linkNode1, *linkNode2;
2420         if(tr2) {
2421           linkNode1 = link12->first;
2422           linkNode2 = link12->second;
2423           if ( tr2 && getQuadrangleNodes( n12, linkNode1, linkNode2, tr1, tr2 ))
2424             Ok12 = true;
2425         }
2426         if(tr3) {
2427           linkNode1 = link13->first;
2428           linkNode2 = link13->second;
2429           if ( tr3 && getQuadrangleNodes( n13, linkNode1, linkNode2, tr1, tr3 ))
2430             Ok13 = true;
2431         }
2432
2433         // Choose a pair to fuse
2434         if ( Ok12 && Ok13 ) {
2435           SMDS_FaceOfNodes quad12 ( n12[ 0 ], n12[ 1 ], n12[ 2 ], n12[ 3 ] );
2436           SMDS_FaceOfNodes quad13 ( n13[ 0 ], n13[ 1 ], n13[ 2 ], n13[ 3 ] );
2437           double aBadRate12 = getBadRate( &quad12, theCrit );
2438           double aBadRate13 = getBadRate( &quad13, theCrit );
2439           if (  aBadRate13 < aBadRate12 )
2440             Ok12 = false;
2441           else
2442             Ok13 = false;
2443         }
2444
2445         // Make quadrangles
2446         // and remove fused elems and removed links from the maps
2447         mapEl_setLi.erase( tr1 );
2448         if ( Ok12 ) {
2449           mapEl_setLi.erase( tr2 );
2450           mapLi_listEl.erase( *link12 );
2451           if(tr1->NbNodes()==3) {
2452             const SMDS_MeshElement* newElem = 0;
2453             newElem = aMesh->AddFace(n12[0], n12[1], n12[2], n12[3] );
2454             myLastCreatedElems.Append(newElem);
2455             AddToSameGroups( newElem, tr1, aMesh );
2456             int aShapeId = tr1->getshapeId();
2457             if ( aShapeId )
2458               {
2459                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2460               }
2461             aMesh->RemoveElement( tr1 );
2462             aMesh->RemoveElement( tr2 );
2463           }
2464           else {
2465             const SMDS_MeshNode* N1 [6];
2466             const SMDS_MeshNode* N2 [6];
2467             GetNodesFromTwoTria(tr1,tr2,N1,N2);
2468             // now we receive following N1 and N2 (using numeration as above image)
2469             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
2470             // i.e. first nodes from both arrays determ new diagonal
2471             const SMDS_MeshNode* aNodes[8];
2472             aNodes[0] = N1[0];
2473             aNodes[1] = N1[1];
2474             aNodes[2] = N2[0];
2475             aNodes[3] = N2[1];
2476             aNodes[4] = N1[3];
2477             aNodes[5] = N2[5];
2478             aNodes[6] = N2[3];
2479             aNodes[7] = N1[5];
2480             const SMDS_MeshElement* newElem = 0;
2481             newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2482                                      aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
2483             myLastCreatedElems.Append(newElem);
2484             AddToSameGroups( newElem, tr1, aMesh );
2485             int aShapeId = tr1->getshapeId();
2486             if ( aShapeId )
2487               {
2488                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2489               }
2490             aMesh->RemoveElement( tr1 );
2491             aMesh->RemoveElement( tr2 );
2492             // remove middle node (9)
2493             GetMeshDS()->RemoveNode( N1[4] );
2494           }
2495         }
2496         else if ( Ok13 ) {
2497           mapEl_setLi.erase( tr3 );
2498           mapLi_listEl.erase( *link13 );
2499           if(tr1->NbNodes()==3) {
2500             const SMDS_MeshElement* newElem = 0;
2501             newElem = aMesh->AddFace(n13[0], n13[1], n13[2], n13[3] );
2502             myLastCreatedElems.Append(newElem);
2503             AddToSameGroups( newElem, tr1, aMesh );
2504             int aShapeId = tr1->getshapeId();
2505             if ( aShapeId )
2506               {
2507                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2508               }
2509             aMesh->RemoveElement( tr1 );
2510             aMesh->RemoveElement( tr3 );
2511           }
2512           else {
2513             const SMDS_MeshNode* N1 [6];
2514             const SMDS_MeshNode* N2 [6];
2515             GetNodesFromTwoTria(tr1,tr3,N1,N2);
2516             // now we receive following N1 and N2 (using numeration as above image)
2517             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
2518             // i.e. first nodes from both arrays determ new diagonal
2519             const SMDS_MeshNode* aNodes[8];
2520             aNodes[0] = N1[0];
2521             aNodes[1] = N1[1];
2522             aNodes[2] = N2[0];
2523             aNodes[3] = N2[1];
2524             aNodes[4] = N1[3];
2525             aNodes[5] = N2[5];
2526             aNodes[6] = N2[3];
2527             aNodes[7] = N1[5];
2528             const SMDS_MeshElement* newElem = 0;
2529             newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2530                                      aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
2531             myLastCreatedElems.Append(newElem);
2532             AddToSameGroups( newElem, tr1, aMesh );
2533             int aShapeId = tr1->getshapeId();
2534             if ( aShapeId )
2535               {
2536                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2537               }
2538             aMesh->RemoveElement( tr1 );
2539             aMesh->RemoveElement( tr3 );
2540             // remove middle node (9)
2541             GetMeshDS()->RemoveNode( N1[4] );
2542           }
2543         }
2544
2545         // Next element to fuse: the rejected one
2546         if ( tr3 )
2547           startElem = Ok12 ? tr3 : tr2;
2548
2549       } // if ( startElem )
2550     } // while ( startElem || !startLinks.empty() )
2551   } // while ( ! mapEl_setLi.empty() )
2552
2553   return true;
2554 }
2555
2556
2557 /*#define DUMPSO(txt) \
2558 //  cout << txt << endl;
2559 //=============================================================================
2560 //
2561 //
2562 //
2563 //=============================================================================
2564 static void swap( int i1, int i2, int idNodes[], gp_Pnt P[] )
2565 {
2566 if ( i1 == i2 )
2567 return;
2568 int tmp = idNodes[ i1 ];
2569 idNodes[ i1 ] = idNodes[ i2 ];
2570 idNodes[ i2 ] = tmp;
2571 gp_Pnt Ptmp = P[ i1 ];
2572 P[ i1 ] = P[ i2 ];
2573 P[ i2 ] = Ptmp;
2574 DUMPSO( i1 << "(" << idNodes[ i2 ] << ") <-> " << i2 << "(" << idNodes[ i1 ] << ")");
2575 }
2576
2577 //=======================================================================
2578 //function : SortQuadNodes
2579 //purpose  : Set 4 nodes of a quadrangle face in a good order.
2580 //           Swap 1<->2 or 2<->3 nodes and correspondingly return
2581 //           1 or 2 else 0.
2582 //=======================================================================
2583
2584 int SMESH_MeshEditor::SortQuadNodes (const SMDS_Mesh * theMesh,
2585 int               idNodes[] )
2586 {
2587   gp_Pnt P[4];
2588   int i;
2589   for ( i = 0; i < 4; i++ ) {
2590     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2591     if ( !n ) return 0;
2592     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2593   }
2594
2595   gp_Vec V1(P[0], P[1]);
2596   gp_Vec V2(P[0], P[2]);
2597   gp_Vec V3(P[0], P[3]);
2598
2599   gp_Vec Cross1 = V1 ^ V2;
2600   gp_Vec Cross2 = V2 ^ V3;
2601
2602   i = 0;
2603   if (Cross1.Dot(Cross2) < 0)
2604   {
2605     Cross1 = V2 ^ V1;
2606     Cross2 = V1 ^ V3;
2607
2608     if (Cross1.Dot(Cross2) < 0)
2609       i = 2;
2610     else
2611       i = 1;
2612     swap ( i, i + 1, idNodes, P );
2613
2614     //     for ( int ii = 0; ii < 4; ii++ ) {
2615     //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2616     //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2617     //     }
2618   }
2619   return i;
2620 }
2621
2622 //=======================================================================
2623 //function : SortHexaNodes
2624 //purpose  : Set 8 nodes of a hexahedron in a good order.
2625 //           Return success status
2626 //=======================================================================
2627
2628 bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh,
2629                                       int               idNodes[] )
2630 {
2631   gp_Pnt P[8];
2632   int i;
2633   DUMPSO( "INPUT: ========================================");
2634   for ( i = 0; i < 8; i++ ) {
2635     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2636     if ( !n ) return false;
2637     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2638     DUMPSO( i << "(" << idNodes[i] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2639   }
2640   DUMPSO( "========================================");
2641
2642
2643   set<int> faceNodes;  // ids of bottom face nodes, to be found
2644   set<int> checkedId1; // ids of tried 2-nd nodes
2645   Standard_Real leastDist = DBL_MAX; // dist of the 4-th node from 123 plane
2646   const Standard_Real tol = 1.e-6;   // tolerance to find nodes in plane
2647   int iMin, iLoop1 = 0;
2648
2649   // Loop to try the 2-nd nodes
2650
2651   while ( leastDist > DBL_MIN && ++iLoop1 < 8 )
2652   {
2653     // Find not checked 2-nd node
2654     for ( i = 1; i < 8; i++ )
2655       if ( checkedId1.find( idNodes[i] ) == checkedId1.end() ) {
2656         int id1 = idNodes[i];
2657         swap ( 1, i, idNodes, P );
2658         checkedId1.insert ( id1 );
2659         break;
2660       }
2661
2662     // Find the 3-d node so that 1-2-3 triangle to be on a hexa face,
2663     // ie that all but meybe one (id3 which is on the same face) nodes
2664     // lay on the same side from the triangle plane.
2665
2666     bool manyInPlane = false; // more than 4 nodes lay in plane
2667     int iLoop2 = 0;
2668     while ( ++iLoop2 < 6 ) {
2669
2670       // get 1-2-3 plane coeffs
2671       Standard_Real A, B, C, D;
2672       gp_Vec N = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2673       if ( N.SquareMagnitude() > gp::Resolution() )
2674       {
2675         gp_Pln pln ( P[0], N );
2676         pln.Coefficients( A, B, C, D );
2677
2678         // find the node (iMin) closest to pln
2679         Standard_Real dist[ 8 ], minDist = DBL_MAX;
2680         set<int> idInPln;
2681         for ( i = 3; i < 8; i++ ) {
2682           dist[i] = A * P[i].X() + B * P[i].Y() + C * P[i].Z() + D;
2683           if ( fabs( dist[i] ) < minDist ) {
2684             minDist = fabs( dist[i] );
2685             iMin = i;
2686           }
2687           if ( fabs( dist[i] ) <= tol )
2688             idInPln.insert( idNodes[i] );
2689         }
2690
2691         // there should not be more than 4 nodes in bottom plane
2692         if ( idInPln.size() > 1 )
2693         {
2694           DUMPSO( "### idInPln.size() = " << idInPln.size());
2695           // idInPlane does not contain the first 3 nodes
2696           if ( manyInPlane || idInPln.size() == 5)
2697             return false; // all nodes in one plane
2698           manyInPlane = true;
2699
2700           // set the 1-st node to be not in plane
2701           for ( i = 3; i < 8; i++ ) {
2702             if ( idInPln.find( idNodes[ i ] ) == idInPln.end() ) {
2703               DUMPSO( "### Reset 0-th node");
2704               swap( 0, i, idNodes, P );
2705               break;
2706             }
2707           }
2708
2709           // reset to re-check second nodes
2710           leastDist = DBL_MAX;
2711           faceNodes.clear();
2712           checkedId1.clear();
2713           iLoop1 = 0;
2714           break; // from iLoop2;
2715         }
2716
2717         // check that the other 4 nodes are on the same side
2718         bool sameSide = true;
2719         bool isNeg = dist[ iMin == 3 ? 4 : 3 ] <= 0.;
2720         for ( i = 3; sameSide && i < 8; i++ ) {
2721           if ( i != iMin )
2722             sameSide = ( isNeg == dist[i] <= 0.);
2723         }
2724
2725         // keep best solution
2726         if ( sameSide && minDist < leastDist ) {
2727           leastDist = minDist;
2728           faceNodes.clear();
2729           faceNodes.insert( idNodes[ 1 ] );
2730           faceNodes.insert( idNodes[ 2 ] );
2731           faceNodes.insert( idNodes[ iMin ] );
2732           DUMPSO( "loop " << iLoop2 << " id2 " << idNodes[ 1 ] << " id3 " << idNodes[ 2 ]
2733                   << " leastDist = " << leastDist);
2734           if ( leastDist <= DBL_MIN )
2735             break;
2736         }
2737       }
2738
2739       // set next 3-d node to check
2740       int iNext = 2 + iLoop2;
2741       if ( iNext < 8 ) {
2742         DUMPSO( "Try 2-nd");
2743         swap ( 2, iNext, idNodes, P );
2744       }
2745     } // while ( iLoop2 < 6 )
2746   } // iLoop1
2747
2748   if ( faceNodes.empty() ) return false;
2749
2750   // Put the faceNodes in proper places
2751   for ( i = 4; i < 8; i++ ) {
2752     if ( faceNodes.find( idNodes[ i ] ) != faceNodes.end() ) {
2753       // find a place to put
2754       int iTo = 1;
2755       while ( faceNodes.find( idNodes[ iTo ] ) != faceNodes.end() )
2756         iTo++;
2757       DUMPSO( "Set faceNodes");
2758       swap ( iTo, i, idNodes, P );
2759     }
2760   }
2761
2762
2763   // Set nodes of the found bottom face in good order
2764   DUMPSO( " Found bottom face: ");
2765   i = SortQuadNodes( theMesh, idNodes );
2766   if ( i ) {
2767     gp_Pnt Ptmp = P[ i ];
2768     P[ i ] = P[ i+1 ];
2769     P[ i+1 ] = Ptmp;
2770   }
2771   //   else
2772   //     for ( int ii = 0; ii < 4; ii++ ) {
2773   //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2774   //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2775   //    }
2776
2777   // Gravity center of the top and bottom faces
2778   gp_Pnt aGCb = ( P[0].XYZ() + P[1].XYZ() + P[2].XYZ() + P[3].XYZ() ) / 4.;
2779   gp_Pnt aGCt = ( P[4].XYZ() + P[5].XYZ() + P[6].XYZ() + P[7].XYZ() ) / 4.;
2780
2781   // Get direction from the bottom to the top face
2782   gp_Vec upDir ( aGCb, aGCt );
2783   Standard_Real upDirSize = upDir.Magnitude();
2784   if ( upDirSize <= gp::Resolution() ) return false;
2785   upDir / upDirSize;
2786
2787   // Assure that the bottom face normal points up
2788   gp_Vec Nb = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2789   Nb += gp_Vec (P[0], P[2]).Crossed( gp_Vec (P[0], P[3]) );
2790   if ( Nb.Dot( upDir ) < 0 ) {
2791     DUMPSO( "Reverse bottom face");
2792     swap( 1, 3, idNodes, P );
2793   }
2794
2795   // Find 5-th node - the one closest to the 1-st among the last 4 nodes.
2796   Standard_Real minDist = DBL_MAX;
2797   for ( i = 4; i < 8; i++ ) {
2798     // projection of P[i] to the plane defined by P[0] and upDir
2799     gp_Pnt Pp = P[i].Translated( upDir * ( upDir.Dot( gp_Vec( P[i], P[0] ))));
2800     Standard_Real sqDist = P[0].SquareDistance( Pp );
2801     if ( sqDist < minDist ) {
2802       minDist = sqDist;
2803       iMin = i;
2804     }
2805   }
2806   DUMPSO( "Set 4-th");
2807   swap ( 4, iMin, idNodes, P );
2808
2809   // Set nodes of the top face in good order
2810   DUMPSO( "Sort top face");
2811   i = SortQuadNodes( theMesh, &idNodes[4] );
2812   if ( i ) {
2813     i += 4;
2814     gp_Pnt Ptmp = P[ i ];
2815     P[ i ] = P[ i+1 ];
2816     P[ i+1 ] = Ptmp;
2817   }
2818
2819   // Assure that direction of the top face normal is from the bottom face
2820   gp_Vec Nt = gp_Vec (P[4], P[5]).Crossed( gp_Vec (P[4], P[6]) );
2821   Nt += gp_Vec (P[4], P[6]).Crossed( gp_Vec (P[4], P[7]) );
2822   if ( Nt.Dot( upDir ) < 0 ) {
2823     DUMPSO( "Reverse top face");
2824     swap( 5, 7, idNodes, P );
2825   }
2826
2827   //   DUMPSO( "OUTPUT: ========================================");
2828   //   for ( i = 0; i < 8; i++ ) {
2829   //     float *p = ugrid->GetPoint(idNodes[i]);
2830   //     DUMPSO( i << "(" << idNodes[i] << ") : " << p[0] << " " << p[1] << " " << p[2]);
2831   //   }
2832
2833   return true;
2834 }*/
2835
2836 //================================================================================
2837 /*!
2838  * \brief Return nodes linked to the given one
2839  * \param theNode - the node
2840  * \param linkedNodes - the found nodes
2841  * \param type - the type of elements to check
2842  *
2843  * Medium nodes are ignored
2844  */
2845 //================================================================================
2846
2847 void SMESH_MeshEditor::GetLinkedNodes( const SMDS_MeshNode* theNode,
2848                                        TIDSortedElemSet &   linkedNodes,
2849                                        SMDSAbs_ElementType  type )
2850 {
2851   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(type);
2852   while ( elemIt->more() )
2853   {
2854     const SMDS_MeshElement* elem = elemIt->next();
2855     if(elem->GetType() == SMDSAbs_0DElement)
2856       continue;
2857
2858     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
2859     if ( elem->GetType() == SMDSAbs_Volume )
2860     {
2861       SMDS_VolumeTool vol( elem );
2862       while ( nodeIt->more() ) {
2863         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2864         if ( theNode != n && vol.IsLinked( theNode, n ))
2865           linkedNodes.insert( n );
2866       }
2867     }
2868     else
2869     {
2870       for ( int i = 0; nodeIt->more(); ++i ) {
2871         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2872         if ( n == theNode ) {
2873           int iBefore = i - 1;
2874           int iAfter  = i + 1;
2875           if ( elem->IsQuadratic() ) {
2876             int nb = elem->NbNodes() / 2;
2877             iAfter  = SMESH_MesherHelper::WrapIndex( iAfter, nb );
2878             iBefore = SMESH_MesherHelper::WrapIndex( iBefore, nb );
2879           }
2880           linkedNodes.insert( elem->GetNodeWrap( iAfter ));
2881           linkedNodes.insert( elem->GetNodeWrap( iBefore ));
2882         }
2883       }
2884     }
2885   }
2886 }
2887
2888 //=======================================================================
2889 //function : laplacianSmooth
2890 //purpose  : pulls theNode toward the center of surrounding nodes directly
2891 //           connected to that node along an element edge
2892 //=======================================================================
2893
2894 void laplacianSmooth(const SMDS_MeshNode*                 theNode,
2895                      const Handle(Geom_Surface)&          theSurface,
2896                      map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2897 {
2898   // find surrounding nodes
2899
2900   TIDSortedElemSet nodeSet;
2901   SMESH_MeshEditor::GetLinkedNodes( theNode, nodeSet, SMDSAbs_Face );
2902
2903   // compute new coodrs
2904
2905   double coord[] = { 0., 0., 0. };
2906   TIDSortedElemSet::iterator nodeSetIt = nodeSet.begin();
2907   for ( ; nodeSetIt != nodeSet.end(); nodeSetIt++ ) {
2908     const SMDS_MeshNode* node = cast2Node(*nodeSetIt);
2909     if ( theSurface.IsNull() ) { // smooth in 3D
2910       coord[0] += node->X();
2911       coord[1] += node->Y();
2912       coord[2] += node->Z();
2913     }
2914     else { // smooth in 2D
2915       ASSERT( theUVMap.find( node ) != theUVMap.end() );
2916       gp_XY* uv = theUVMap[ node ];
2917       coord[0] += uv->X();
2918       coord[1] += uv->Y();
2919     }
2920   }
2921   int nbNodes = nodeSet.size();
2922   if ( !nbNodes )
2923     return;
2924   coord[0] /= nbNodes;
2925   coord[1] /= nbNodes;
2926
2927   if ( !theSurface.IsNull() ) {
2928     ASSERT( theUVMap.find( theNode ) != theUVMap.end() );
2929     theUVMap[ theNode ]->SetCoord( coord[0], coord[1] );
2930     gp_Pnt p3d = theSurface->Value( coord[0], coord[1] );
2931     coord[0] = p3d.X();
2932     coord[1] = p3d.Y();
2933     coord[2] = p3d.Z();
2934   }
2935   else
2936     coord[2] /= nbNodes;
2937
2938   // move node
2939
2940   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(coord[0],coord[1],coord[2]);
2941 }
2942
2943 //=======================================================================
2944 //function : centroidalSmooth
2945 //purpose  : pulls theNode toward the element-area-weighted centroid of the
2946 //           surrounding elements
2947 //=======================================================================
2948
2949 void centroidalSmooth(const SMDS_MeshNode*                 theNode,
2950                       const Handle(Geom_Surface)&          theSurface,
2951                       map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2952 {
2953   gp_XYZ aNewXYZ(0.,0.,0.);
2954   SMESH::Controls::Area anAreaFunc;
2955   double totalArea = 0.;
2956   int nbElems = 0;
2957
2958   // compute new XYZ
2959
2960   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(SMDSAbs_Face);
2961   while ( elemIt->more() )
2962   {
2963     const SMDS_MeshElement* elem = elemIt->next();
2964     nbElems++;
2965
2966     gp_XYZ elemCenter(0.,0.,0.);
2967     SMESH::Controls::TSequenceOfXYZ aNodePoints;
2968     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2969     int nn = elem->NbNodes();
2970     if(elem->IsQuadratic()) nn = nn/2;
2971     int i=0;
2972     //while ( itN->more() ) {
2973     while ( i<nn ) {
2974       const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>( itN->next() );
2975       i++;
2976       gp_XYZ aP( aNode->X(), aNode->Y(), aNode->Z() );
2977       aNodePoints.push_back( aP );
2978       if ( !theSurface.IsNull() ) { // smooth in 2D
2979         ASSERT( theUVMap.find( aNode ) != theUVMap.end() );
2980         gp_XY* uv = theUVMap[ aNode ];
2981         aP.SetCoord( uv->X(), uv->Y(), 0. );
2982       }
2983       elemCenter += aP;
2984     }
2985     double elemArea = anAreaFunc.GetValue( aNodePoints );
2986     totalArea += elemArea;
2987     elemCenter /= nn;
2988     aNewXYZ += elemCenter * elemArea;
2989   }
2990   aNewXYZ /= totalArea;
2991   if ( !theSurface.IsNull() ) {
2992     theUVMap[ theNode ]->SetCoord( aNewXYZ.X(), aNewXYZ.Y() );
2993     aNewXYZ = theSurface->Value( aNewXYZ.X(), aNewXYZ.Y() ).XYZ();
2994   }
2995
2996   // move node
2997
2998   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(aNewXYZ.X(),aNewXYZ.Y(),aNewXYZ.Z());
2999 }
3000
3001 //=======================================================================
3002 //function : getClosestUV
3003 //purpose  : return UV of closest projection
3004 //=======================================================================
3005
3006 static bool getClosestUV (Extrema_GenExtPS& projector,
3007                           const gp_Pnt&     point,
3008                           gp_XY &           result)
3009 {
3010   projector.Perform( point );
3011   if ( projector.IsDone() ) {
3012     double u, v, minVal = DBL_MAX;
3013     for ( int i = projector.NbExt(); i > 0; i-- )
3014 #if OCC_VERSION_LARGE > 0x06040000 // Porting to OCCT6.5.1
3015       if ( projector.SquareDistance( i ) < minVal ) {
3016         minVal = projector.SquareDistance( i );
3017 #else
3018       if ( projector.Value( i ) < minVal ) {
3019         minVal = projector.Value( i );
3020 #endif
3021         projector.Point( i ).Parameter( u, v );
3022       }
3023     result.SetCoord( u, v );
3024     return true;
3025   }
3026   return false;
3027 }
3028
3029 //=======================================================================
3030 //function : Smooth
3031 //purpose  : Smooth theElements during theNbIterations or until a worst
3032 //           element has aspect ratio <= theTgtAspectRatio.
3033 //           Aspect Ratio varies in range [1.0, inf].
3034 //           If theElements is empty, the whole mesh is smoothed.
3035 //           theFixedNodes contains additionally fixed nodes. Nodes built
3036 //           on edges and boundary nodes are always fixed.
3037 //=======================================================================
3038
3039 void SMESH_MeshEditor::Smooth (TIDSortedElemSet &          theElems,
3040                                set<const SMDS_MeshNode*> & theFixedNodes,
3041                                const SmoothMethod          theSmoothMethod,
3042                                const int                   theNbIterations,
3043                                double                      theTgtAspectRatio,
3044                                const bool                  the2D)
3045 {
3046   myLastCreatedElems.Clear();
3047   myLastCreatedNodes.Clear();
3048
3049   MESSAGE((theSmoothMethod==LAPLACIAN ? "LAPLACIAN" : "CENTROIDAL") << "--::Smooth()");
3050
3051   if ( theTgtAspectRatio < 1.0 )
3052     theTgtAspectRatio = 1.0;
3053
3054   const double disttol = 1.e-16;
3055
3056   SMESH::Controls::AspectRatio aQualityFunc;
3057
3058   SMESHDS_Mesh* aMesh = GetMeshDS();
3059
3060   if ( theElems.empty() ) {
3061     // add all faces to theElems
3062     SMDS_FaceIteratorPtr fIt = aMesh->facesIterator();
3063     while ( fIt->more() ) {
3064       const SMDS_MeshElement* face = fIt->next();
3065       theElems.insert( face );
3066     }
3067   }
3068   // get all face ids theElems are on
3069   set< int > faceIdSet;
3070   TIDSortedElemSet::iterator itElem;
3071   if ( the2D )
3072     for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
3073       int fId = FindShape( *itElem );
3074       // check that corresponding submesh exists and a shape is face
3075       if (fId &&
3076           faceIdSet.find( fId ) == faceIdSet.end() &&
3077           aMesh->MeshElements( fId )) {
3078         TopoDS_Shape F = aMesh->IndexToShape( fId );
3079         if ( !F.IsNull() && F.ShapeType() == TopAbs_FACE )
3080           faceIdSet.insert( fId );
3081       }
3082     }
3083   faceIdSet.insert( 0 ); // to smooth elements that are not on any TopoDS_Face
3084
3085   // ===============================================
3086   // smooth elements on each TopoDS_Face separately
3087   // ===============================================
3088
3089   set< int >::reverse_iterator fId = faceIdSet.rbegin(); // treate 0 fId at the end
3090   for ( ; fId != faceIdSet.rend(); ++fId ) {
3091     // get face surface and submesh
3092     Handle(Geom_Surface) surface;
3093     SMESHDS_SubMesh* faceSubMesh = 0;
3094     TopoDS_Face face;
3095     double fToler2 = 0, f,l;
3096     double u1 = 0, u2 = 0, v1 = 0, v2 = 0;
3097     bool isUPeriodic = false, isVPeriodic = false;
3098     if ( *fId ) {
3099       face = TopoDS::Face( aMesh->IndexToShape( *fId ));
3100       surface = BRep_Tool::Surface( face );
3101       faceSubMesh = aMesh->MeshElements( *fId );
3102       fToler2 = BRep_Tool::Tolerance( face );
3103       fToler2 *= fToler2 * 10.;
3104       isUPeriodic = surface->IsUPeriodic();
3105       if ( isUPeriodic )
3106         surface->UPeriod();
3107       isVPeriodic = surface->IsVPeriodic();
3108       if ( isVPeriodic )
3109         surface->VPeriod();
3110       surface->Bounds( u1, u2, v1, v2 );
3111     }
3112     // ---------------------------------------------------------
3113     // for elements on a face, find movable and fixed nodes and
3114     // compute UV for them
3115     // ---------------------------------------------------------
3116     bool checkBoundaryNodes = false;
3117     bool isQuadratic = false;
3118     set<const SMDS_MeshNode*> setMovableNodes;
3119     map< const SMDS_MeshNode*, gp_XY* > uvMap, uvMap2;
3120     list< gp_XY > listUV; // uvs the 2 uvMaps refer to
3121     list< const SMDS_MeshElement* > elemsOnFace;
3122
3123     Extrema_GenExtPS projector;
3124     GeomAdaptor_Surface surfAdaptor;
3125     if ( !surface.IsNull() ) {
3126       surfAdaptor.Load( surface );
3127       projector.Initialize( surfAdaptor, 20,20, 1e-5,1e-5 );
3128     }
3129     int nbElemOnFace = 0;
3130     itElem = theElems.begin();
3131     // loop on not yet smoothed elements: look for elems on a face
3132     while ( itElem != theElems.end() ) {
3133       if ( faceSubMesh && nbElemOnFace == faceSubMesh->NbElements() )
3134         break; // all elements found
3135
3136       const SMDS_MeshElement* elem = *itElem;
3137       if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() < 3 ||
3138            ( faceSubMesh && !faceSubMesh->Contains( elem ))) {
3139         ++itElem;
3140         continue;
3141       }
3142       elemsOnFace.push_back( elem );
3143       theElems.erase( itElem++ );
3144       nbElemOnFace++;
3145
3146       if ( !isQuadratic )
3147         isQuadratic = elem->IsQuadratic();
3148
3149       // get movable nodes of elem
3150       const SMDS_MeshNode* node;
3151       SMDS_TypeOfPosition posType;
3152       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
3153       int nn = 0, nbn =  elem->NbNodes();
3154       if(elem->IsQuadratic())
3155         nbn = nbn/2;
3156       while ( nn++ < nbn ) {
3157         node = static_cast<const SMDS_MeshNode*>( itN->next() );
3158         const SMDS_PositionPtr& pos = node->GetPosition();
3159         posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
3160         if (posType != SMDS_TOP_EDGE &&
3161             posType != SMDS_TOP_VERTEX &&
3162             theFixedNodes.find( node ) == theFixedNodes.end())
3163         {
3164           // check if all faces around the node are on faceSubMesh
3165           // because a node on edge may be bound to face
3166           SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
3167           bool all = true;
3168           if ( faceSubMesh ) {
3169             while ( eIt->more() && all ) {
3170               const SMDS_MeshElement* e = eIt->next();
3171               all = faceSubMesh->Contains( e );
3172             }
3173           }
3174           if ( all )
3175             setMovableNodes.insert( node );
3176           else
3177             checkBoundaryNodes = true;
3178         }
3179         if ( posType == SMDS_TOP_3DSPACE )
3180           checkBoundaryNodes = true;
3181       }
3182
3183       if ( surface.IsNull() )
3184         continue;
3185
3186       // get nodes to check UV
3187       list< const SMDS_MeshNode* > uvCheckNodes;
3188       itN = elem->nodesIterator();
3189       nn = 0; nbn =  elem->NbNodes();
3190       if(elem->IsQuadratic())
3191         nbn = nbn/2;
3192       while ( nn++ < nbn ) {
3193         node = static_cast<const SMDS_MeshNode*>( itN->next() );
3194         if ( uvMap.find( node ) == uvMap.end() )
3195           uvCheckNodes.push_back( node );
3196         // add nodes of elems sharing node
3197         //         SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
3198         //         while ( eIt->more() ) {
3199         //           const SMDS_MeshElement* e = eIt->next();
3200         //           if ( e != elem ) {
3201         //             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3202         //             while ( nIt->more() ) {
3203         //               const SMDS_MeshNode* n =
3204         //                 static_cast<const SMDS_MeshNode*>( nIt->next() );
3205         //               if ( uvMap.find( n ) == uvMap.end() )
3206         //                 uvCheckNodes.push_back( n );
3207         //             }
3208         //           }
3209         //         }
3210       }
3211       // check UV on face
3212       list< const SMDS_MeshNode* >::iterator n = uvCheckNodes.begin();
3213       for ( ; n != uvCheckNodes.end(); ++n ) {
3214         node = *n;
3215         gp_XY uv( 0, 0 );
3216         const SMDS_PositionPtr& pos = node->GetPosition();
3217         posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
3218         // get existing UV
3219         switch ( posType ) {
3220         case SMDS_TOP_FACE: {
3221           SMDS_FacePosition* fPos = ( SMDS_FacePosition* ) pos;
3222           uv.SetCoord( fPos->GetUParameter(), fPos->GetVParameter() );
3223           break;
3224         }
3225         case SMDS_TOP_EDGE: {
3226           TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
3227           Handle(Geom2d_Curve) pcurve;
3228           if ( !S.IsNull() && S.ShapeType() == TopAbs_EDGE )
3229             pcurve = BRep_Tool::CurveOnSurface( TopoDS::Edge( S ), face, f,l );
3230           if ( !pcurve.IsNull() ) {
3231             double u = (( SMDS_EdgePosition* ) pos )->GetUParameter();
3232             uv = pcurve->Value( u ).XY();
3233           }
3234           break;
3235         }
3236         case SMDS_TOP_VERTEX: {
3237           TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
3238           if ( !S.IsNull() && S.ShapeType() == TopAbs_VERTEX )
3239             uv = BRep_Tool::Parameters( TopoDS::Vertex( S ), face ).XY();
3240           break;
3241         }
3242         default:;
3243         }
3244         // check existing UV
3245         bool project = true;
3246         gp_Pnt pNode ( node->X(), node->Y(), node->Z() );
3247         double dist1 = DBL_MAX, dist2 = 0;
3248         if ( posType != SMDS_TOP_3DSPACE ) {
3249           dist1 = pNode.SquareDistance( surface->Value( uv.X(), uv.Y() ));
3250           project = dist1 > fToler2;
3251         }
3252         if ( project ) { // compute new UV
3253           gp_XY newUV;
3254           if ( !getClosestUV( projector, pNode, newUV )) {
3255             MESSAGE("Node Projection Failed " << node);
3256           }
3257           else {
3258             if ( isUPeriodic )
3259               newUV.SetX( ElCLib::InPeriod( newUV.X(), u1, u2 ));
3260             if ( isVPeriodic )
3261               newUV.SetY( ElCLib::InPeriod( newUV.Y(), v1, v2 ));
3262             // check new UV
3263             if ( posType != SMDS_TOP_3DSPACE )
3264               dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() ));
3265             if ( dist2 < dist1 )
3266               uv = newUV;
3267           }
3268         }
3269         // store UV in the map
3270         listUV.push_back( uv );
3271         uvMap.insert( make_pair( node, &listUV.back() ));
3272       }
3273     } // loop on not yet smoothed elements
3274
3275     if ( !faceSubMesh || nbElemOnFace != faceSubMesh->NbElements() )
3276       checkBoundaryNodes = true;
3277
3278     // fix nodes on mesh boundary
3279
3280     if ( checkBoundaryNodes ) {
3281       map< SMESH_TLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
3282       map< SMESH_TLink, int >::iterator link_nb;
3283       // put all elements links to linkNbMap
3284       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3285       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3286         const SMDS_MeshElement* elem = (*elemIt);
3287         int nbn =  elem->NbCornerNodes();
3288         // loop on elem links: insert them in linkNbMap
3289         for ( int iN = 0; iN < nbn; ++iN ) {
3290           const SMDS_MeshNode* n1 = elem->GetNode( iN );
3291           const SMDS_MeshNode* n2 = elem->GetNode(( iN+1 ) % nbn);
3292           SMESH_TLink link( n1, n2 );
3293           link_nb = linkNbMap.insert( make_pair( link, 0 )).first;
3294           link_nb->second++;
3295         }
3296       }
3297       // remove nodes that are in links encountered only once from setMovableNodes
3298       for ( link_nb = linkNbMap.begin(); link_nb != linkNbMap.end(); ++link_nb ) {
3299         if ( link_nb->second == 1 ) {
3300           setMovableNodes.erase( link_nb->first.node1() );
3301           setMovableNodes.erase( link_nb->first.node2() );
3302         }
3303       }
3304     }
3305
3306     // -----------------------------------------------------
3307     // for nodes on seam edge, compute one more UV ( uvMap2 );
3308     // find movable nodes linked to nodes on seam and which
3309     // are to be smoothed using the second UV ( uvMap2 )
3310     // -----------------------------------------------------
3311
3312     set<const SMDS_MeshNode*> nodesNearSeam; // to smooth using uvMap2
3313     if ( !surface.IsNull() ) {
3314       TopExp_Explorer eExp( face, TopAbs_EDGE );
3315       for ( ; eExp.More(); eExp.Next() ) {
3316         TopoDS_Edge edge = TopoDS::Edge( eExp.Current() );
3317         if ( !BRep_Tool::IsClosed( edge, face ))
3318           continue;
3319         SMESHDS_SubMesh* sm = aMesh->MeshElements( edge );
3320         if ( !sm ) continue;
3321         // find out which parameter varies for a node on seam
3322         double f,l;
3323         gp_Pnt2d uv1, uv2;
3324         Handle(Geom2d_Curve) pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3325         if ( pcurve.IsNull() ) continue;
3326         uv1 = pcurve->Value( f );
3327         edge.Reverse();
3328         pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3329         if ( pcurve.IsNull() ) continue;
3330         uv2 = pcurve->Value( f );
3331         int iPar = Abs( uv1.X() - uv2.X() ) > Abs( uv1.Y() - uv2.Y() ) ? 1 : 2;
3332         // assure uv1 < uv2
3333         if ( uv1.Coord( iPar ) > uv2.Coord( iPar )) {
3334           gp_Pnt2d tmp = uv1; uv1 = uv2; uv2 = tmp;
3335         }
3336         // get nodes on seam and its vertices
3337         list< const SMDS_MeshNode* > seamNodes;
3338         SMDS_NodeIteratorPtr nSeamIt = sm->GetNodes();
3339         while ( nSeamIt->more() ) {
3340           const SMDS_MeshNode* node = nSeamIt->next();
3341           if ( !isQuadratic || !IsMedium( node ))
3342             seamNodes.push_back( node );
3343         }
3344         TopExp_Explorer vExp( edge, TopAbs_VERTEX );
3345         for ( ; vExp.More(); vExp.Next() ) {
3346           sm = aMesh->MeshElements( vExp.Current() );
3347           if ( sm ) {
3348             nSeamIt = sm->GetNodes();
3349             while ( nSeamIt->more() )
3350               seamNodes.push_back( nSeamIt->next() );
3351           }
3352         }
3353         // loop on nodes on seam
3354         list< const SMDS_MeshNode* >::iterator noSeIt = seamNodes.begin();
3355         for ( ; noSeIt != seamNodes.end(); ++noSeIt ) {
3356           const SMDS_MeshNode* nSeam = *noSeIt;
3357           map< const SMDS_MeshNode*, gp_XY* >::iterator n_uv = uvMap.find( nSeam );
3358           if ( n_uv == uvMap.end() )
3359             continue;
3360           // set the first UV
3361           n_uv->second->SetCoord( iPar, uv1.Coord( iPar ));
3362           // set the second UV
3363           listUV.push_back( *n_uv->second );
3364           listUV.back().SetCoord( iPar, uv2.Coord( iPar ));
3365           if ( uvMap2.empty() )
3366             uvMap2 = uvMap; // copy the uvMap contents
3367           uvMap2[ nSeam ] = &listUV.back();
3368
3369           // collect movable nodes linked to ones on seam in nodesNearSeam
3370           SMDS_ElemIteratorPtr eIt = nSeam->GetInverseElementIterator(SMDSAbs_Face);
3371           while ( eIt->more() ) {
3372             const SMDS_MeshElement* e = eIt->next();
3373             int nbUseMap1 = 0, nbUseMap2 = 0;
3374             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3375             int nn = 0, nbn =  e->NbNodes();
3376             if(e->IsQuadratic()) nbn = nbn/2;
3377             while ( nn++ < nbn )
3378             {
3379               const SMDS_MeshNode* n =
3380                 static_cast<const SMDS_MeshNode*>( nIt->next() );
3381               if (n == nSeam ||
3382                   setMovableNodes.find( n ) == setMovableNodes.end() )
3383                 continue;
3384               // add only nodes being closer to uv2 than to uv1
3385               gp_Pnt pMid (0.5 * ( n->X() + nSeam->X() ),
3386                            0.5 * ( n->Y() + nSeam->Y() ),
3387                            0.5 * ( n->Z() + nSeam->Z() ));
3388               gp_XY uv;
3389               getClosestUV( projector, pMid, uv );
3390               if ( uv.Coord( iPar ) > uvMap[ n ]->Coord( iPar ) ) {
3391                 nodesNearSeam.insert( n );
3392                 nbUseMap2++;
3393               }
3394               else
3395                 nbUseMap1++;
3396             }
3397             // for centroidalSmooth all element nodes must
3398             // be on one side of a seam
3399             if ( theSmoothMethod == CENTROIDAL && nbUseMap1 && nbUseMap2 ) {
3400               SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3401               nn = 0;
3402               while ( nn++ < nbn ) {
3403                 const SMDS_MeshNode* n =
3404                   static_cast<const SMDS_MeshNode*>( nIt->next() );
3405                 setMovableNodes.erase( n );
3406               }
3407             }
3408           }
3409         } // loop on nodes on seam
3410       } // loop on edge of a face
3411     } // if ( !face.IsNull() )
3412
3413     if ( setMovableNodes.empty() ) {
3414       MESSAGE( "Face id : " << *fId << " - NO SMOOTHING: no nodes to move!!!");
3415       continue; // goto next face
3416     }
3417
3418     // -------------
3419     // SMOOTHING //
3420     // -------------
3421
3422     int it = -1;
3423     double maxRatio = -1., maxDisplacement = -1.;
3424     set<const SMDS_MeshNode*>::iterator nodeToMove;
3425     for ( it = 0; it < theNbIterations; it++ ) {
3426       maxDisplacement = 0.;
3427       nodeToMove = setMovableNodes.begin();
3428       for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3429         const SMDS_MeshNode* node = (*nodeToMove);
3430         gp_XYZ aPrevPos ( node->X(), node->Y(), node->Z() );
3431
3432         // smooth
3433         bool map2 = ( nodesNearSeam.find( node ) != nodesNearSeam.end() );
3434         if ( theSmoothMethod == LAPLACIAN )
3435           laplacianSmooth( node, surface, map2 ? uvMap2 : uvMap );
3436         else
3437           centroidalSmooth( node, surface, map2 ? uvMap2 : uvMap );
3438
3439         // node displacement
3440         gp_XYZ aNewPos ( node->X(), node->Y(), node->Z() );
3441         Standard_Real aDispl = (aPrevPos - aNewPos).SquareModulus();
3442         if ( aDispl > maxDisplacement )
3443           maxDisplacement = aDispl;
3444       }
3445       // no node movement => exit
3446       //if ( maxDisplacement < 1.e-16 ) {
3447       if ( maxDisplacement < disttol ) {
3448         MESSAGE("-- no node movement --");
3449         break;
3450       }
3451
3452       // check elements quality
3453       maxRatio  = 0;
3454       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3455       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3456         const SMDS_MeshElement* elem = (*elemIt);
3457         if ( !elem || elem->GetType() != SMDSAbs_Face )
3458           continue;
3459         SMESH::Controls::TSequenceOfXYZ aPoints;
3460         if ( aQualityFunc.GetPoints( elem, aPoints )) {
3461           double aValue = aQualityFunc.GetValue( aPoints );
3462           if ( aValue > maxRatio )
3463             maxRatio = aValue;
3464         }
3465       }
3466       if ( maxRatio <= theTgtAspectRatio ) {
3467         MESSAGE("-- quality achived --");
3468         break;
3469       }
3470       if (it+1 == theNbIterations) {
3471         MESSAGE("-- Iteration limit exceeded --");
3472       }
3473     } // smoothing iterations
3474
3475     MESSAGE(" Face id: " << *fId <<
3476             " Nb iterstions: " << it <<
3477             " Displacement: " << maxDisplacement <<
3478             " Aspect Ratio " << maxRatio);
3479
3480     // ---------------------------------------
3481     // new nodes positions are computed,
3482     // record movement in DS and set new UV
3483     // ---------------------------------------
3484     nodeToMove = setMovableNodes.begin();
3485     for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3486       SMDS_MeshNode* node = const_cast< SMDS_MeshNode* > (*nodeToMove);
3487       aMesh->MoveNode( node, node->X(), node->Y(), node->Z() );
3488       map< const SMDS_MeshNode*, gp_XY* >::iterator node_uv = uvMap.find( node );
3489       if ( node_uv != uvMap.end() ) {
3490         gp_XY* uv = node_uv->second;
3491         node->SetPosition
3492           ( SMDS_PositionPtr( new SMDS_FacePosition( uv->X(), uv->Y() )));
3493       }
3494     }
3495
3496     // move medium nodes of quadratic elements
3497     if ( isQuadratic )
3498     {
3499       SMESH_MesherHelper helper( *GetMesh() );
3500       if ( !face.IsNull() )
3501         helper.SetSubShape( face );
3502       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3503       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3504         const SMDS_VtkFace* QF =
3505           dynamic_cast<const SMDS_VtkFace*> (*elemIt);
3506         if(QF && QF->IsQuadratic()) {
3507           vector<const SMDS_MeshNode*> Ns;
3508           Ns.reserve(QF->NbNodes()+1);
3509           SMDS_ElemIteratorPtr anIter = QF->interlacedNodesElemIterator();
3510           while ( anIter->more() )
3511             Ns.push_back( cast2Node(anIter->next()) );
3512           Ns.push_back( Ns[0] );
3513           double x, y, z;
3514           for(int i=0; i<QF->NbNodes(); i=i+2) {
3515             if ( !surface.IsNull() ) {
3516               gp_XY uv1 = helper.GetNodeUV( face, Ns[i], Ns[i+2] );
3517               gp_XY uv2 = helper.GetNodeUV( face, Ns[i+2], Ns[i] );
3518               gp_XY uv = ( uv1 + uv2 ) / 2.;
3519               gp_Pnt xyz = surface->Value( uv.X(), uv.Y() );
3520               x = xyz.X(); y = xyz.Y(); z = xyz.Z();
3521             }
3522             else {
3523               x = (Ns[i]->X() + Ns[i+2]->X())/2;
3524               y = (Ns[i]->Y() + Ns[i+2]->Y())/2;
3525               z = (Ns[i]->Z() + Ns[i+2]->Z())/2;
3526             }
3527             if( fabs( Ns[i+1]->X() - x ) > disttol ||
3528                 fabs( Ns[i+1]->Y() - y ) > disttol ||
3529                 fabs( Ns[i+1]->Z() - z ) > disttol ) {
3530               // we have to move i+1 node
3531               aMesh->MoveNode( Ns[i+1], x, y, z );
3532             }
3533           }
3534         }
3535       }
3536     }
3537
3538   } // loop on face ids
3539
3540 }
3541
3542 //=======================================================================
3543 //function : isReverse
3544 //purpose  : Return true if normal of prevNodes is not co-directied with
3545 //           gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]).
3546 //           iNotSame is where prevNodes and nextNodes are different.
3547 //           If result is true then future volume orientation is OK
3548 //=======================================================================
3549
3550 static bool isReverse(const SMDS_MeshElement*             face,
3551                       const vector<const SMDS_MeshNode*>& prevNodes,
3552                       const vector<const SMDS_MeshNode*>& nextNodes,
3553                       const int                           iNotSame)
3554 {
3555
3556   SMESH_TNodeXYZ pP = prevNodes[ iNotSame ];
3557   SMESH_TNodeXYZ pN = nextNodes[ iNotSame ];
3558   gp_XYZ extrDir( pN - pP ), faceNorm;
3559   SMESH_Algo::FaceNormal( face, faceNorm, /*normalized=*/false );
3560
3561   return faceNorm * extrDir < 0.0;
3562 }
3563
3564 //=======================================================================
3565 /*!
3566  * \brief Create elements by sweeping an element
3567  * \param elem - element to sweep
3568  * \param newNodesItVec - nodes generated from each node of the element
3569  * \param newElems - generated elements
3570  * \param nbSteps - number of sweeping steps
3571  * \param srcElements - to append elem for each generated element
3572  */
3573 //=======================================================================
3574
3575 void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement*               elem,
3576                                     const vector<TNodeOfNodeListMapItr> & newNodesItVec,
3577                                     list<const SMDS_MeshElement*>&        newElems,
3578                                     const int                             nbSteps,
3579                                     SMESH_SequenceOfElemPtr&              srcElements)
3580 {
3581   //MESSAGE("sweepElement " << nbSteps);
3582   SMESHDS_Mesh* aMesh = GetMeshDS();
3583
3584   const int           nbNodes = elem->NbNodes();
3585   const int         nbCorners = elem->NbCornerNodes();
3586   SMDSAbs_EntityType baseType = elem->GetEntityType(); /* it can change in case of
3587                                                           polyhedron creation !!! */
3588   // Loop on elem nodes:
3589   // find new nodes and detect same nodes indices
3590   vector < list< const SMDS_MeshNode* >::const_iterator > itNN( nbNodes );
3591   vector<const SMDS_MeshNode*> prevNod( nbNodes );
3592   vector<const SMDS_MeshNode*> nextNod( nbNodes );
3593   vector<const SMDS_MeshNode*> midlNod( nbNodes );
3594
3595   int iNode, nbSame = 0, nbDouble = 0, iNotSameNode = 0;
3596   vector<int> sames(nbNodes);
3597   vector<bool> isSingleNode(nbNodes);
3598
3599   for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3600     TNodeOfNodeListMapItr                        nnIt = newNodesItVec[ iNode ];
3601     const SMDS_MeshNode*                         node = nnIt->first;
3602     const list< const SMDS_MeshNode* > & listNewNodes = nnIt->second;
3603     if ( listNewNodes.empty() )
3604       return;
3605
3606     itNN   [ iNode ] = listNewNodes.begin();
3607     prevNod[ iNode ] = node;
3608     nextNod[ iNode ] = listNewNodes.front();
3609
3610     isSingleNode[iNode] = (listNewNodes.size()==nbSteps); /* medium node of quadratic or
3611                                                              corner node of linear */
3612     if ( prevNod[ iNode ] != nextNod [ iNode ])
3613       nbDouble += !isSingleNode[iNode];
3614
3615     if( iNode < nbCorners ) { // check corners only
3616       if ( prevNod[ iNode ] == nextNod [ iNode ])
3617         sames[nbSame++] = iNode;
3618       else
3619         iNotSameNode = iNode;
3620     }
3621   }
3622
3623   if ( nbSame == nbNodes || nbSame > 2) {
3624     MESSAGE( " Too many same nodes of element " << elem->GetID() );
3625     return;
3626   }
3627
3628   if ( elem->GetType() == SMDSAbs_Face && !isReverse( elem, prevNod, nextNod, iNotSameNode ))
3629   {
3630     // fix nodes order to have bottom normal external
3631     if ( baseType == SMDSEntity_Polygon )
3632     {
3633       std::reverse( itNN.begin(), itNN.end() );
3634       std::reverse( prevNod.begin(), prevNod.end() );
3635       std::reverse( midlNod.begin(), midlNod.end() );
3636       std::reverse( nextNod.begin(), nextNod.end() );
3637       std::reverse( isSingleNode.begin(), isSingleNode.end() );
3638     }
3639     else
3640     {
3641       const vector<int>& ind = SMDS_MeshCell::reverseSmdsOrder( baseType );
3642       SMDS_MeshCell::applyInterlace( ind, itNN );
3643       SMDS_MeshCell::applyInterlace( ind, prevNod );
3644       SMDS_MeshCell::applyInterlace( ind, nextNod );
3645       SMDS_MeshCell::applyInterlace( ind, midlNod );
3646       SMDS_MeshCell::applyInterlace( ind, isSingleNode );
3647       if ( nbSame > 0 )
3648       {
3649         sames[nbSame] = iNotSameNode;
3650         for ( int j = 0; j <= nbSame; ++j )
3651           for ( size_t i = 0; i < ind.size(); ++i )
3652             if ( ind[i] == sames[j] )
3653             {
3654               sames[j] = i;
3655               break;
3656             }
3657         iNotSameNode = sames[nbSame];
3658       }
3659     }
3660   }
3661
3662   int iSameNode = 0, iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0;
3663   if ( nbSame > 0 ) {
3664     iSameNode    = sames[ nbSame-1 ];
3665     iBeforeSame  = ( iSameNode + nbCorners - 1 ) % nbCorners;
3666     iAfterSame   = ( iSameNode + 1 ) % nbCorners;
3667     iOpposSame   = ( iSameNode - 2 < 0  ? iSameNode + 2 : iSameNode - 2 );
3668   }
3669
3670   // make new elements
3671   for (int iStep = 0; iStep < nbSteps; iStep++ )
3672   {
3673     // get next nodes
3674     for ( iNode = 0; iNode < nbNodes; iNode++ )
3675     {
3676       midlNod[ iNode ] = isSingleNode[iNode] ? 0 : *itNN[ iNode ]++;
3677       nextNod[ iNode ] = *itNN[ iNode ]++;
3678     }
3679
3680     SMDS_MeshElement* aNewElem = 0;
3681     /*if(!elem->IsPoly())*/ {
3682       switch ( baseType ) {
3683       case SMDSEntity_0D:
3684       case SMDSEntity_Node: { // sweep NODE
3685         if ( nbSame == 0 ) {
3686           if ( isSingleNode[0] )
3687             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ] );
3688           else
3689             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ], midlNod[ 0 ] );
3690         }
3691         else
3692           return;
3693         break;
3694       }
3695       case SMDSEntity_Edge: { // sweep EDGE
3696         if ( nbDouble == 0 )
3697         {
3698           if ( nbSame == 0 ) // ---> quadrangle
3699             aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3700                                       nextNod[ 1 ], nextNod[ 0 ] );
3701           else               // ---> triangle
3702             aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3703                                       nextNod[ iNotSameNode ] );
3704         }
3705         else                 // ---> polygon
3706         {
3707           vector<const SMDS_MeshNode*> poly_nodes;
3708           poly_nodes.push_back( prevNod[0] );
3709           poly_nodes.push_back( prevNod[1] );
3710           if ( prevNod[1] != nextNod[1] )
3711           {
3712             if ( midlNod[1]) poly_nodes.push_back( midlNod[1]);
3713             poly_nodes.push_back( nextNod[1] );
3714           }
3715           if ( prevNod[0] != nextNod[0] )
3716           {
3717             poly_nodes.push_back( nextNod[0] );
3718             if ( midlNod[0]) poly_nodes.push_back( midlNod[0]);
3719           }
3720           switch ( poly_nodes.size() ) {
3721           case 3:
3722             aNewElem = aMesh->AddFace( poly_nodes[ 0 ], poly_nodes[ 1 ], poly_nodes[ 2 ]);
3723             break;
3724           case 4:
3725             aNewElem = aMesh->AddFace( poly_nodes[ 0 ], poly_nodes[ 1 ],
3726                                        poly_nodes[ 2 ], poly_nodes[ 3 ]);
3727             break;
3728           default:
3729             aNewElem = aMesh->AddPolygonalFace (poly_nodes);
3730           }
3731         }
3732         break;
3733       }
3734       case SMDSEntity_Triangle: // TRIANGLE --->
3735         {
3736           if ( nbDouble > 0 ) break;
3737           if ( nbSame == 0 )       // ---> pentahedron
3738             aNewElem = aMesh->AddVolume (prevNod[ 0 ], prevNod[ 1 ], prevNod[ 2 ],
3739                                          nextNod[ 0 ], nextNod[ 1 ], nextNod[ 2 ] );
3740
3741           else if ( nbSame == 1 )  // ---> pyramid
3742             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
3743                                          nextNod[ iAfterSame ],  nextNod[ iBeforeSame ],
3744                                          nextNod[ iSameNode ]);
3745
3746           else // 2 same nodes:       ---> tetrahedron
3747             aNewElem = aMesh->AddVolume (prevNod[ 0 ], prevNod[ 1 ], prevNod[ 2 ],
3748                                          nextNod[ iNotSameNode ]);
3749           break;
3750         }
3751       case SMDSEntity_Quad_Edge: // sweep quadratic EDGE --->
3752         {
3753           if ( nbSame == 2 )
3754             return;
3755           if ( nbDouble+nbSame == 2 )
3756           {
3757             if(nbSame==0) {      // ---> quadratic quadrangle
3758               aNewElem = aMesh->AddFace(prevNod[0], prevNod[1], nextNod[1], nextNod[0],
3759                                         prevNod[2], midlNod[1], nextNod[2], midlNod[0]);
3760             }
3761             else { //(nbSame==1) // ---> quadratic triangle
3762               if(sames[0]==2) {
3763                 return; // medium node on axis
3764               }
3765               else if(sames[0]==0)
3766                 aNewElem = aMesh->AddFace(prevNod[0], nextNod[1], prevNod[1],
3767                                           nextNod[2], midlNod[1], prevNod[2]);
3768               else // sames[0]==1
3769                 aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], prevNod[1],
3770                                           midlNod[0], nextNod[2], prevNod[2]);
3771             }
3772           }
3773           else if ( nbDouble == 3 )
3774           {
3775             if ( nbSame == 0 ) {  // ---> bi-quadratic quadrangle
3776               aNewElem = aMesh->AddFace(prevNod[0], prevNod[1], nextNod[1], nextNod[0],
3777                                         prevNod[2], midlNod[1], nextNod[2], midlNod[0], midlNod[2]);
3778             }
3779           }
3780           else
3781             return;
3782           break;
3783         }
3784       case SMDSEntity_Quadrangle: { // sweep QUADRANGLE --->
3785         if ( nbDouble > 0 ) break;
3786
3787         if ( nbSame == 0 )       // ---> hexahedron
3788           aNewElem = aMesh->AddVolume (prevNod[ 0 ], prevNod[ 1 ], prevNod[ 2 ], prevNod[ 3 ],
3789                                        nextNod[ 0 ], nextNod[ 1 ], nextNod[ 2 ], nextNod[ 3 ]);
3790
3791         else if ( nbSame == 1 ) { // ---> pyramid + pentahedron
3792           aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
3793                                        nextNod[ iAfterSame ],  nextNod[ iBeforeSame ],
3794                                        nextNod[ iSameNode ]);
3795           newElems.push_back( aNewElem );
3796           aNewElem = aMesh->AddVolume (prevNod[ iAfterSame ],  prevNod[ iOpposSame ],
3797                                        prevNod[ iBeforeSame ], nextNod[ iAfterSame ],
3798                                        nextNod[ iOpposSame ],  nextNod[ iBeforeSame ] );
3799         }
3800         else if ( nbSame == 2 ) { // ---> pentahedron
3801           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] )
3802             // iBeforeSame is same too
3803             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iOpposSame ],
3804                                          nextNod[ iOpposSame ],  prevNod[ iSameNode ],
3805                                          prevNod[ iAfterSame ],  nextNod[ iAfterSame ]);
3806           else
3807             // iAfterSame is same too
3808             aNewElem = aMesh->AddVolume (prevNod[ iSameNode ],   prevNod[ iBeforeSame ],
3809                                          nextNod[ iBeforeSame ], prevNod[ iAfterSame ],
3810                                          prevNod[ iOpposSame ],  nextNod[ iOpposSame ]);
3811         }
3812         break;
3813       }
3814       case SMDSEntity_Quad_Triangle: { // sweep Quadratic TRIANGLE --->
3815         if ( nbDouble+nbSame != 3 ) break;
3816         if(nbSame==0) {
3817           // --->  pentahedron with 15 nodes
3818           aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
3819                                        nextNod[0], nextNod[1], nextNod[2],
3820                                        prevNod[3], prevNod[4], prevNod[5],
3821                                        nextNod[3], nextNod[4], nextNod[5],
3822                                        midlNod[0], midlNod[1], midlNod[2]);
3823         }
3824         else if(nbSame==1) {
3825           // --->  2d order pyramid of 13 nodes
3826           int apex = iSameNode;
3827           int i0 = ( apex + 1 ) % nbCorners;
3828           int i1 = ( apex - 1 + nbCorners ) % nbCorners;
3829           int i0a = apex + 3;
3830           int i1a = i1 + 3;
3831           int i01 = i0 + 3;
3832           aNewElem = aMesh->AddVolume(prevNod[i1], prevNod[i0],
3833                                       nextNod[i0], nextNod[i1], prevNod[apex],
3834                                       prevNod[i01], midlNod[i0],
3835                                       nextNod[i01], midlNod[i1],
3836                                       prevNod[i1a], prevNod[i0a],
3837                                       nextNod[i0a], nextNod[i1a]);
3838         }
3839         else if(nbSame==2) {
3840           // --->  2d order tetrahedron of 10 nodes
3841           int n1 = iNotSameNode;
3842           int n2 = ( n1 + 1             ) % nbCorners;
3843           int n3 = ( n1 + nbCorners - 1 ) % nbCorners;
3844           int n12 = n1 + 3;
3845           int n23 = n2 + 3;
3846           int n31 = n3 + 3;
3847           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], prevNod[n3], nextNod[n1],
3848                                        prevNod[n12], prevNod[n23], prevNod[n31],
3849                                        midlNod[n1], nextNod[n12], nextNod[n31]);
3850         }
3851         break;
3852       }
3853       case SMDSEntity_Quad_Quadrangle: { // sweep Quadratic QUADRANGLE --->
3854         if( nbSame == 0 ) {
3855           if ( nbDouble != 4 ) break;
3856           // --->  hexahedron with 20 nodes
3857           aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
3858                                        nextNod[0], nextNod[1], nextNod[2], nextNod[3],
3859                                        prevNod[4], prevNod[5], prevNod[6], prevNod[7],
3860                                        nextNod[4], nextNod[5], nextNod[6], nextNod[7],
3861                                        midlNod[0], midlNod[1], midlNod[2], midlNod[3]);
3862         }
3863         else if(nbSame==1) {
3864           // ---> pyramid + pentahedron - can not be created since it is needed
3865           // additional middle node at the center of face
3866           INFOS( " Sweep for face " << elem->GetID() << " can not be created" );
3867           return;
3868         }
3869         else if( nbSame == 2 ) {
3870           if ( nbDouble != 2 ) break;
3871           // --->  2d order Pentahedron with 15 nodes
3872           int n1,n2,n4,n5;
3873           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] ) {
3874             // iBeforeSame is same too
3875             n1 = iBeforeSame;
3876             n2 = iOpposSame;
3877             n4 = iSameNode;
3878             n5 = iAfterSame;
3879           }
3880           else {
3881             // iAfterSame is same too
3882             n1 = iSameNode;
3883             n2 = iBeforeSame;
3884             n4 = iAfterSame;
3885             n5 = iOpposSame;
3886           }
3887           int n12 = n2 + 4;
3888           int n45 = n4 + 4;
3889           int n14 = n1 + 4;
3890           int n25 = n5 + 4;
3891           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], nextNod[n2],
3892                                        prevNod[n4], prevNod[n5], nextNod[n5],
3893                                        prevNod[n12], midlNod[n2], nextNod[n12],
3894                                        prevNod[n45], midlNod[n5], nextNod[n45],
3895                                        prevNod[n14], prevNod[n25], nextNod[n25]);
3896         }
3897         break;
3898       }
3899       case SMDSEntity_BiQuad_Quadrangle: { // sweep BiQuadratic QUADRANGLE --->
3900
3901         if( nbSame == 0 && nbDouble == 9 ) {
3902           // --->  tri-quadratic hexahedron with 27 nodes
3903           aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
3904                                        nextNod[0], nextNod[1], nextNod[2], nextNod[3],
3905                                        prevNod[4], prevNod[5], prevNod[6], prevNod[7],
3906                                        nextNod[4], nextNod[5], nextNod[6], nextNod[7],
3907                                        midlNod[0], midlNod[1], midlNod[2], midlNod[3],
3908                                        prevNod[8], // bottom center
3909                                        midlNod[4], midlNod[5], midlNod[6], midlNod[7],
3910                                        nextNod[8], // top center
3911                                        midlNod[8]);// elem center
3912         }
3913         else
3914         {
3915           return;
3916         }
3917         break;
3918       }
3919       case SMDSEntity_Polygon: { // sweep POLYGON
3920
3921         if ( nbNodes == 6 && nbSame == 0 && nbDouble == 0 ) {
3922           // --->  hexagonal prism
3923           aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
3924                                        prevNod[3], prevNod[4], prevNod[5],
3925                                        nextNod[0], nextNod[1], nextNod[2],
3926                                        nextNod[3], nextNod[4], nextNod[5]);
3927         }
3928         break;
3929       }
3930       case SMDSEntity_Ball:
3931         return;
3932
3933       default:
3934         break;
3935       }
3936     }
3937
3938     if ( !aNewElem && elem->GetType() == SMDSAbs_Face ) // try to create a polyherdal prism
3939     {
3940       if ( baseType != SMDSEntity_Polygon )
3941       {
3942         const std::vector<int>& ind = SMDS_MeshCell::interlacedSmdsOrder(baseType);
3943         SMDS_MeshCell::applyInterlace( ind, prevNod );
3944         SMDS_MeshCell::applyInterlace( ind, nextNod );
3945         SMDS_MeshCell::applyInterlace( ind, midlNod );
3946         SMDS_MeshCell::applyInterlace( ind, itNN );
3947         SMDS_MeshCell::applyInterlace( ind, isSingleNode );
3948         baseType = SMDSEntity_Polygon; // WARNING: change baseType !!!!
3949       }
3950       vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3951       vector<int> quantities (nbNodes + 2);
3952       polyedre_nodes.clear();
3953       quantities.clear();
3954
3955       // bottom of prism
3956       for (int inode = 0; inode < nbNodes; inode++)
3957         polyedre_nodes.push_back( prevNod[inode] );
3958       quantities.push_back( nbNodes );
3959
3960       // top of prism
3961       polyedre_nodes.push_back( nextNod[0] );
3962       for (int inode = nbNodes; inode-1; --inode )
3963         polyedre_nodes.push_back( nextNod[inode-1] );
3964       quantities.push_back( nbNodes );
3965
3966       // side faces
3967       for (int iface = 0; iface < nbNodes; iface++)
3968       {
3969         const int prevNbNodes = polyedre_nodes.size();
3970         int inextface = (iface+1) % nbNodes;
3971         polyedre_nodes.push_back( prevNod[inextface] );
3972         polyedre_nodes.push_back( prevNod[iface] );
3973         if ( prevNod[iface] != nextNod[iface] )
3974         {
3975           if ( midlNod[ iface ]) polyedre_nodes.push_back( midlNod[ iface ]);
3976           polyedre_nodes.push_back( nextNod[iface] );
3977         }
3978         if ( prevNod[inextface] != nextNod[inextface] )
3979         {
3980           polyedre_nodes.push_back( nextNod[inextface] );
3981           if ( midlNod[ inextface ]) polyedre_nodes.push_back( midlNod[ inextface ]);
3982         }
3983         const int nbFaceNodes = polyedre_nodes.size() - prevNbNodes;
3984         if ( nbFaceNodes > 2 )
3985           quantities.push_back( nbFaceNodes );
3986         else // degenerated face
3987           polyedre_nodes.resize( prevNbNodes );
3988       }
3989       aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3990     }
3991
3992     if ( aNewElem ) {
3993       newElems.push_back( aNewElem );
3994       myLastCreatedElems.Append(aNewElem);
3995       srcElements.Append( elem );
3996     }
3997
3998     // set new prev nodes
3999     for ( iNode = 0; iNode < nbNodes; iNode++ )
4000       prevNod[ iNode ] = nextNod[ iNode ];
4001
4002   } // for steps
4003 }
4004
4005 //=======================================================================
4006 /*!
4007  * \brief Create 1D and 2D elements around swept elements
4008  * \param mapNewNodes - source nodes and ones generated from them
4009  * \param newElemsMap - source elements and ones generated from them
4010  * \param elemNewNodesMap - nodes generated from each node of each element
4011  * \param elemSet - all swept elements
4012  * \param nbSteps - number of sweeping steps
4013  * \param srcElements - to append elem for each generated element
4014  */
4015 //=======================================================================
4016
4017 void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap &     mapNewNodes,
4018                                   TElemOfElemListMap &     newElemsMap,
4019                                   TElemOfVecOfNnlmiMap &   elemNewNodesMap,
4020                                   TIDSortedElemSet&        elemSet,
4021                                   const int                nbSteps,
4022                                   SMESH_SequenceOfElemPtr& srcElements)
4023 {
4024   ASSERT( newElemsMap.size() == elemNewNodesMap.size() );
4025   SMESHDS_Mesh* aMesh = GetMeshDS();
4026
4027   // Find nodes belonging to only one initial element - sweep them to get edges.
4028
4029   TNodeOfNodeListMapItr nList = mapNewNodes.begin();
4030   for ( ; nList != mapNewNodes.end(); nList++ )
4031   {
4032     const SMDS_MeshNode* node =
4033       static_cast<const SMDS_MeshNode*>( nList->first );
4034     if ( newElemsMap.count( node ))
4035       continue; // node was extruded into edge
4036     SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
4037     int nbInitElems = 0;
4038     const SMDS_MeshElement* el = 0;
4039     SMDSAbs_ElementType highType = SMDSAbs_Edge; // count most complex elements only
4040     while ( eIt->more() && nbInitElems < 2 ) {
4041       el = eIt->next();
4042       SMDSAbs_ElementType type = el->GetType();
4043       if ( type == SMDSAbs_Volume || type < highType ) continue;
4044       if ( type > highType ) {
4045         nbInitElems = 0;
4046         highType = type;
4047       }
4048       nbInitElems += elemSet.count(el);
4049     }
4050     if ( nbInitElems < 2 ) {
4051       bool NotCreateEdge = el && el->IsMediumNode(node);
4052       if(!NotCreateEdge) {
4053         vector<TNodeOfNodeListMapItr> newNodesItVec( 1, nList );
4054         list<const SMDS_MeshElement*> newEdges;
4055         sweepElement( node, newNodesItVec, newEdges, nbSteps, srcElements );
4056       }
4057     }
4058   }
4059
4060   // Make a ceiling for each element ie an equal element of last new nodes.
4061   // Find free links of faces - make edges and sweep them into faces.
4062
4063   TElemOfElemListMap::iterator   itElem      = newElemsMap.begin();
4064   TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin();
4065   for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ )
4066   {
4067     const SMDS_MeshElement* elem = itElem->first;
4068     vector<TNodeOfNodeListMapItr>& vecNewNodes = itElemNodes->second;
4069
4070     if(itElem->second.size()==0) continue;
4071
4072     const bool isQuadratic = elem->IsQuadratic();
4073
4074     if ( elem->GetType() == SMDSAbs_Edge ) {
4075       // create a ceiling edge
4076       if ( !isQuadratic ) {
4077         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
4078                                vecNewNodes[ 1 ]->second.back())) {
4079           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
4080                                                    vecNewNodes[ 1 ]->second.back()));
4081           srcElements.Append( myLastCreatedElems.Last() );
4082         }
4083       }
4084       else {
4085         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
4086                                vecNewNodes[ 1 ]->second.back(),
4087                                vecNewNodes[ 2 ]->second.back())) {
4088           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
4089                                                    vecNewNodes[ 1 ]->second.back(),
4090                                                    vecNewNodes[ 2 ]->second.back()));
4091           srcElements.Append( myLastCreatedElems.Last() );
4092         }
4093       }
4094     }
4095     if ( elem->GetType() != SMDSAbs_Face )
4096       continue;
4097
4098     bool hasFreeLinks = false;
4099
4100     TIDSortedElemSet avoidSet;
4101     avoidSet.insert( elem );
4102
4103     set<const SMDS_MeshNode*> aFaceLastNodes;
4104     int iNode, nbNodes = vecNewNodes.size();
4105     if ( !isQuadratic ) {
4106       // loop on the face nodes
4107       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
4108         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
4109         // look for free links of the face
4110         int iNext = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1;
4111         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
4112         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
4113         // check if a link is free
4114         if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
4115           hasFreeLinks = true;
4116           // make an edge and a ceiling for a new edge
4117           if ( !aMesh->FindEdge( n1, n2 )) {
4118             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // free link edge
4119             srcElements.Append( myLastCreatedElems.Last() );
4120           }
4121           n1 = vecNewNodes[ iNode ]->second.back();
4122           n2 = vecNewNodes[ iNext ]->second.back();
4123           if ( !aMesh->FindEdge( n1, n2 )) {
4124             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // ceiling edge
4125             srcElements.Append( myLastCreatedElems.Last() );
4126           }
4127         }
4128       }
4129     }
4130     else { // elem is quadratic face
4131       int nbn = nbNodes/2;
4132       for ( iNode = 0; iNode < nbn; iNode++ ) {
4133         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
4134         int iNext = ( iNode + 1 == nbn ) ? 0 : iNode + 1;
4135         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
4136         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
4137         const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first;
4138         // check if a link is free
4139         if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet ) &&
4140              ! SMESH_MeshEditor::FindFaceInSet ( n1, n3, elemSet, avoidSet ) &&
4141              ! SMESH_MeshEditor::FindFaceInSet ( n3, n2, elemSet, avoidSet ) ) {
4142           hasFreeLinks = true;
4143           // make an edge and a ceiling for a new edge
4144           // find medium node
4145           if ( !aMesh->FindEdge( n1, n2, n3 )) {
4146             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // free link edge
4147             srcElements.Append( myLastCreatedElems.Last() );
4148           }
4149           n1 = vecNewNodes[ iNode ]->second.back();
4150           n2 = vecNewNodes[ iNext ]->second.back();
4151           n3 = vecNewNodes[ iNode+nbn ]->second.back();
4152           if ( !aMesh->FindEdge( n1, n2, n3 )) {
4153             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // ceiling edge
4154             srcElements.Append( myLastCreatedElems.Last() );
4155           }
4156         }
4157       }
4158       for ( iNode = nbn; iNode < nbNodes; iNode++ ) {
4159         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
4160       }
4161     }
4162
4163     // sweep free links into faces
4164
4165     if ( hasFreeLinks )  {
4166       list<const SMDS_MeshElement*> & newVolumes = itElem->second;
4167       int iVol, volNb, nbVolumesByStep = newVolumes.size() / nbSteps;
4168
4169       set<const SMDS_MeshNode*> initNodeSet, topNodeSet, faceNodeSet;
4170       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
4171         initNodeSet.insert( vecNewNodes[ iNode ]->first );
4172         topNodeSet .insert( vecNewNodes[ iNode ]->second.back() );
4173       }
4174       for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) {
4175         list<const SMDS_MeshElement*>::iterator v = newVolumes.begin();
4176         std::advance( v, volNb );
4177         // find indices of free faces of a volume and their source edges
4178         list< int > freeInd;
4179         list< const SMDS_MeshElement* > srcEdges; // source edges of free faces
4180         SMDS_VolumeTool vTool( *v, /*ignoreCentralNodes=*/false );
4181         int iF, nbF = vTool.NbFaces();
4182         for ( iF = 0; iF < nbF; iF ++ ) {
4183           if (vTool.IsFreeFace( iF ) &&
4184               vTool.GetFaceNodes( iF, faceNodeSet ) &&
4185               initNodeSet != faceNodeSet) // except an initial face
4186           {
4187             if ( nbSteps == 1 && faceNodeSet == topNodeSet )
4188               continue;
4189             freeInd.push_back( iF );
4190             // find source edge of a free face iF
4191             vector<const SMDS_MeshNode*> commonNodes; // shared by the initial and free faces
4192             commonNodes.resize( initNodeSet.size(), NULL ); // avoid spoiling memory
4193             std::set_intersection( faceNodeSet.begin(), faceNodeSet.end(),
4194                                    initNodeSet.begin(), initNodeSet.end(),
4195                                    commonNodes.begin());
4196             if ( (*v)->IsQuadratic() )
4197               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1],commonNodes[2]));
4198             else
4199               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1]));
4200 #ifdef _DEBUG_
4201             if ( !srcEdges.back() )
4202             {
4203               cout << "SMESH_MeshEditor::makeWalls(), no source edge found for a free face #"
4204                    << iF << " of volume #" << vTool.ID() << endl;
4205             }
4206 #endif
4207           }
4208         }
4209         if ( freeInd.empty() )
4210           continue;
4211
4212         // create faces for all steps;
4213         // if such a face has been already created by sweep of edge,
4214         // assure that its orientation is OK
4215         for ( int iStep = 0; iStep < nbSteps; iStep++ ) {
4216           vTool.Set( *v, /*ignoreCentralNodes=*/false );
4217           vTool.SetExternalNormal();
4218           const int nextShift = vTool.IsForward() ? +1 : -1;
4219           list< int >::iterator ind = freeInd.begin();
4220           list< const SMDS_MeshElement* >::iterator srcEdge = srcEdges.begin();
4221           for ( ; ind != freeInd.end(); ++ind, ++srcEdge ) // loop on free faces
4222           {
4223             const SMDS_MeshNode** nodes = vTool.GetFaceNodes( *ind );
4224             int nbn = vTool.NbFaceNodes( *ind );
4225             const SMDS_MeshElement * f = 0;
4226             if ( nbn == 3 )              ///// triangle
4227             {
4228               f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]);
4229               if ( !f ||
4230                    nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ]) + nextShift ))
4231               {
4232                 const SMDS_MeshNode* newOrder[3] = { nodes[ 1 - nextShift ],
4233                                                      nodes[ 1 ],
4234                                                      nodes[ 1 + nextShift ] };
4235                 if ( f )
4236                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4237                 else
4238                   myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ], newOrder[ 1 ],
4239                                                             newOrder[ 2 ] ));
4240               }
4241             }
4242             else if ( nbn == 4 )       ///// quadrangle
4243             {
4244               f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]);
4245               if ( !f ||
4246                    nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ]) + nextShift ))
4247               {
4248                 const SMDS_MeshNode* newOrder[4] = { nodes[ 0 ], nodes[ 2-nextShift ],
4249                                                      nodes[ 2 ], nodes[ 2+nextShift ] };
4250                 if ( f )
4251                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4252                 else
4253                   myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ], newOrder[ 1 ],
4254                                                             newOrder[ 2 ], newOrder[ 3 ]));
4255               }
4256             }
4257             else if ( nbn == 6 && isQuadratic ) /////// quadratic triangle
4258             {
4259               f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[1], nodes[3], nodes[5] );
4260               if ( !f ||
4261                    nodes[2] != f->GetNodeWrap( f->GetNodeIndex( nodes[0] ) + 2*nextShift ))
4262               {
4263                 const SMDS_MeshNode* newOrder[6] = { nodes[2 - 2*nextShift],
4264                                                      nodes[2],
4265                                                      nodes[2 + 2*nextShift],
4266                                                      nodes[3 - 2*nextShift],
4267                                                      nodes[3],
4268                                                      nodes[3 + 2*nextShift]};
4269                 if ( f )
4270                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4271                 else
4272                   myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ],
4273                                                             newOrder[ 1 ],
4274                                                             newOrder[ 2 ],
4275                                                             newOrder[ 3 ],
4276                                                             newOrder[ 4 ],
4277                                                             newOrder[ 5 ] ));
4278               }
4279             }
4280             else if ( nbn == 8 && isQuadratic ) /////// quadratic quadrangle
4281             {
4282               f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[6],
4283                                    nodes[1], nodes[3], nodes[5], nodes[7] );
4284               if ( !f ||
4285                    nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 2*nextShift ))
4286               {
4287                 const SMDS_MeshNode* newOrder[8] = { nodes[0],
4288                                                      nodes[4 - 2*nextShift],
4289                                                      nodes[4],
4290                                                      nodes[4 + 2*nextShift],
4291                                                      nodes[1],
4292                                                      nodes[5 - 2*nextShift],
4293                                                      nodes[5],
4294                                                      nodes[5 + 2*nextShift] };
4295                 if ( f )
4296                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4297                 else
4298                   myLastCreatedElems.Append(aMesh->AddFace(newOrder[ 0 ], newOrder[ 1 ],
4299                                                            newOrder[ 2 ], newOrder[ 3 ],
4300                                                            newOrder[ 4 ], newOrder[ 5 ],
4301                                                            newOrder[ 6 ], newOrder[ 7 ]));
4302               }
4303             }
4304             else if ( nbn == 9 && isQuadratic ) /////// bi-quadratic quadrangle
4305             {
4306               f = aMesh->FindElement( vector<const SMDS_MeshNode*>( nodes, nodes+nbn ),
4307                                       SMDSAbs_Face, /*noMedium=*/false);
4308               if ( !f ||
4309                    nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 2*nextShift ))
4310               {
4311                 const SMDS_MeshNode* newOrder[9] = { nodes[0],
4312                                                      nodes[4 - 2*nextShift],
4313                                                      nodes[4],
4314                                                      nodes[4 + 2*nextShift],
4315                                                      nodes[1],
4316                                                      nodes[5 - 2*nextShift],
4317                                                      nodes[5],
4318                                                      nodes[5 + 2*nextShift],
4319                                                      nodes[8] };
4320                 if ( f )
4321                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4322                 else
4323                   myLastCreatedElems.Append(aMesh->AddFace(newOrder[ 0 ], newOrder[ 1 ],
4324                                                            newOrder[ 2 ], newOrder[ 3 ],
4325                                                            newOrder[ 4 ], newOrder[ 5 ],
4326                                                            newOrder[ 6 ], newOrder[ 7 ],
4327                                                            newOrder[ 8 ]));
4328               }
4329             }
4330             else  //////// polygon
4331             {
4332               vector<const SMDS_MeshNode*> polygon_nodes ( nodes, nodes+nbn );
4333               const SMDS_MeshFace * f = aMesh->FindFace( polygon_nodes );
4334               if ( !f ||
4335                    nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + nextShift ))
4336               {
4337                 if ( !vTool.IsForward() )
4338                   std::reverse( polygon_nodes.begin(), polygon_nodes.end());
4339                 if ( f )
4340                   aMesh->ChangeElementNodes( f, &polygon_nodes[0], nbn );
4341                 else
4342                   AddElement(polygon_nodes, SMDSAbs_Face, polygon_nodes.size()>4);
4343               }
4344             }
4345
4346             while ( srcElements.Length() < myLastCreatedElems.Length() )
4347               srcElements.Append( *srcEdge );
4348
4349           }  // loop on free faces
4350
4351           // go to the next volume
4352           iVol = 0;
4353           while ( iVol++ < nbVolumesByStep ) v++;
4354
4355         } // loop on steps
4356       } // loop on volumes of one step
4357     } // sweep free links into faces
4358
4359     // Make a ceiling face with a normal external to a volume
4360
4361     SMDS_VolumeTool lastVol( itElem->second.back(), /*ignoreCentralNodes=*/false );
4362
4363     int iF = lastVol.GetFaceIndex( aFaceLastNodes );
4364     if ( iF >= 0 ) {
4365       lastVol.SetExternalNormal();
4366       const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF );
4367       int nbn = lastVol.NbFaceNodes( iF );
4368       if ( nbn == 3 ) {
4369         if (!hasFreeLinks ||
4370             !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]))
4371           myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
4372       }
4373       else if ( nbn == 4 )
4374       {
4375         if (!hasFreeLinks ||
4376             !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]))
4377           myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]));
4378       }
4379       else if ( nbn == 6 && isQuadratic )
4380       {
4381         if (!hasFreeLinks ||
4382             !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[1], nodes[3], nodes[5]) )
4383           myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
4384                                                    nodes[1], nodes[3], nodes[5]));
4385       }
4386       else if ( nbn == 8 && isQuadratic )
4387       {
4388         if (!hasFreeLinks ||
4389             !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[6],
4390                              nodes[1], nodes[3], nodes[5], nodes[7]) )
4391           myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4392                                                    nodes[1], nodes[3], nodes[5], nodes[7]));
4393       }
4394       else if ( nbn == 9 && isQuadratic )
4395       {
4396         if (!hasFreeLinks ||
4397             !aMesh->FindElement(vector<const SMDS_MeshNode*>( nodes, nodes+nbn ),
4398                                 SMDSAbs_Face, /*noMedium=*/false) )
4399           myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4400                                                    nodes[1], nodes[3], nodes[5], nodes[7],
4401                                                    nodes[8]));
4402       }
4403       else {
4404         vector<const SMDS_MeshNode*> polygon_nodes ( nodes, nodes + nbn );
4405         if (!hasFreeLinks || !aMesh->FindFace(polygon_nodes))
4406           myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
4407       }
4408
4409       while ( srcElements.Length() < myLastCreatedElems.Length() )
4410         srcElements.Append( myLastCreatedElems.Last() );
4411     }
4412   } // loop on swept elements
4413 }
4414
4415 //=======================================================================
4416 //function : RotationSweep
4417 //purpose  :
4418 //=======================================================================
4419
4420 SMESH_MeshEditor::PGroupIDs
4421 SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems,
4422                                 const gp_Ax1&      theAxis,
4423                                 const double       theAngle,
4424                                 const int          theNbSteps,
4425                                 const double       theTol,
4426                                 const bool         theMakeGroups,
4427                                 const bool         theMakeWalls)
4428 {
4429   myLastCreatedElems.Clear();
4430   myLastCreatedNodes.Clear();
4431
4432   // source elements for each generated one
4433   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4434
4435   MESSAGE( "RotationSweep()");
4436   gp_Trsf aTrsf;
4437   aTrsf.SetRotation( theAxis, theAngle );
4438   gp_Trsf aTrsf2;
4439   aTrsf2.SetRotation( theAxis, theAngle/2. );
4440
4441   gp_Lin aLine( theAxis );
4442   double aSqTol = theTol * theTol;
4443
4444   SMESHDS_Mesh* aMesh = GetMeshDS();
4445
4446   TNodeOfNodeListMap mapNewNodes;
4447   TElemOfVecOfNnlmiMap mapElemNewNodes;
4448   TElemOfElemListMap newElemsMap;
4449
4450   const bool isQuadraticMesh = bool( myMesh->NbEdges(ORDER_QUADRATIC) +
4451                                      myMesh->NbFaces(ORDER_QUADRATIC) +
4452                                      myMesh->NbVolumes(ORDER_QUADRATIC) );
4453   // loop on theElems
4454   TIDSortedElemSet::iterator itElem;
4455   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4456     const SMDS_MeshElement* elem = *itElem;
4457     if ( !elem || elem->GetType() == SMDSAbs_Volume )
4458       continue;
4459     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4460     newNodesItVec.reserve( elem->NbNodes() );
4461
4462     // loop on elem nodes
4463     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4464     while ( itN->more() )
4465     {
4466       // check if a node has been already sweeped
4467       const SMDS_MeshNode* node = cast2Node( itN->next() );
4468
4469       gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4470       double coord[3];
4471       aXYZ.Coord( coord[0], coord[1], coord[2] );
4472       bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4473
4474       TNodeOfNodeListMapItr nIt =
4475         mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4476       list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4477       if ( listNewNodes.empty() )
4478       {
4479         // check if we are to create medium nodes between corner ones
4480         bool needMediumNodes = false;
4481         if ( isQuadraticMesh )
4482         {
4483           SMDS_ElemIteratorPtr it = node->GetInverseElementIterator();
4484           while (it->more() && !needMediumNodes )
4485           {
4486             const SMDS_MeshElement* invElem = it->next();
4487             if ( invElem != elem && !theElems.count( invElem )) continue;
4488             needMediumNodes = ( invElem->IsQuadratic() && !invElem->IsMediumNode(node) );
4489             if ( !needMediumNodes && invElem->GetEntityType() == SMDSEntity_BiQuad_Quadrangle )
4490               needMediumNodes = true;
4491           }
4492         }
4493
4494         // make new nodes
4495         const SMDS_MeshNode * newNode = node;
4496         for ( int i = 0; i < theNbSteps; i++ ) {
4497           if ( !isOnAxis ) {
4498             if ( needMediumNodes )  // create a medium node
4499             {
4500               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4501               newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4502               myLastCreatedNodes.Append(newNode);
4503               srcNodes.Append( node );
4504               listNewNodes.push_back( newNode );
4505               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4506             }
4507             else {
4508               aTrsf.Transforms( coord[0], coord[1], coord[2] );
4509             }
4510             // create a corner node
4511             newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4512             myLastCreatedNodes.Append(newNode);
4513             srcNodes.Append( node );
4514             listNewNodes.push_back( newNode );
4515           }
4516           else {
4517             listNewNodes.push_back( newNode );
4518             // if ( needMediumNodes )
4519             //   listNewNodes.push_back( newNode );
4520           }
4521         }
4522       }
4523       newNodesItVec.push_back( nIt );
4524     }
4525     // make new elements
4526     sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems );
4527   }
4528
4529   if ( theMakeWalls )
4530     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, theNbSteps, srcElems );
4531
4532   PGroupIDs newGroupIDs;
4533   if ( theMakeGroups )
4534     newGroupIDs = generateGroups( srcNodes, srcElems, "rotated");
4535
4536   return newGroupIDs;
4537 }
4538
4539
4540 //=======================================================================
4541 //function : CreateNode
4542 //purpose  :
4543 //=======================================================================
4544 const SMDS_MeshNode* SMESH_MeshEditor::CreateNode(const double x,
4545                                                   const double y,
4546                                                   const double z,
4547                                                   const double tolnode,
4548                                                   SMESH_SequenceOfNode& aNodes)
4549 {
4550   // myLastCreatedElems.Clear();
4551   // myLastCreatedNodes.Clear();
4552
4553   gp_Pnt P1(x,y,z);
4554   SMESHDS_Mesh * aMesh = myMesh->GetMeshDS();
4555
4556   // try to search in sequence of existing nodes
4557   // if aNodes.Length()>0 we 'nave to use given sequence
4558   // else - use all nodes of mesh
4559   if(aNodes.Length()>0) {
4560     int i;
4561     for(i=1; i<=aNodes.Length(); i++) {
4562       gp_Pnt P2(aNodes.Value(i)->X(),aNodes.Value(i)->Y(),aNodes.Value(i)->Z());
4563       if(P1.Distance(P2)<tolnode)
4564         return aNodes.Value(i);
4565     }
4566   }
4567   else {
4568     SMDS_NodeIteratorPtr itn = aMesh->nodesIterator();
4569     while(itn->more()) {
4570       const SMDS_MeshNode* aN = static_cast<const SMDS_MeshNode*> (itn->next());
4571       gp_Pnt P2(aN->X(),aN->Y(),aN->Z());
4572       if(P1.Distance(P2)<tolnode)
4573         return aN;
4574     }
4575   }
4576
4577   // create new node and return it
4578   const SMDS_MeshNode* NewNode = aMesh->AddNode(x,y,z);
4579   //myLastCreatedNodes.Append(NewNode);
4580   return NewNode;
4581 }
4582
4583
4584 //=======================================================================
4585 //function : ExtrusionSweep
4586 //purpose  :
4587 //=======================================================================
4588
4589 SMESH_MeshEditor::PGroupIDs
4590 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
4591                                   const gp_Vec&       theStep,
4592                                   const int           theNbSteps,
4593                                   TElemOfElemListMap& newElemsMap,
4594                                   const bool          theMakeGroups,
4595                                   const int           theFlags,
4596                                   const double        theTolerance)
4597 {
4598   ExtrusParam aParams;
4599   aParams.myDir = gp_Dir(theStep);
4600   aParams.myNodes.Clear();
4601   aParams.mySteps = new TColStd_HSequenceOfReal;
4602   int i;
4603   for(i=1; i<=theNbSteps; i++)
4604     aParams.mySteps->Append(theStep.Magnitude());
4605
4606   return
4607     ExtrusionSweep(theElems,aParams,newElemsMap,theMakeGroups,theFlags,theTolerance);
4608 }
4609
4610
4611 //=======================================================================
4612 //function : ExtrusionSweep
4613 //purpose  :
4614 //=======================================================================
4615
4616 SMESH_MeshEditor::PGroupIDs
4617 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
4618                                   ExtrusParam&        theParams,
4619                                   TElemOfElemListMap& newElemsMap,
4620                                   const bool          theMakeGroups,
4621                                   const int           theFlags,
4622                                   const double        theTolerance)
4623 {
4624   myLastCreatedElems.Clear();
4625   myLastCreatedNodes.Clear();
4626
4627   // source elements for each generated one
4628   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4629
4630   SMESHDS_Mesh* aMesh = GetMeshDS();
4631
4632   int nbsteps = theParams.mySteps->Length();
4633
4634   TNodeOfNodeListMap mapNewNodes;
4635   //TNodeOfNodeVecMap mapNewNodes;
4636   TElemOfVecOfNnlmiMap mapElemNewNodes;
4637   //TElemOfVecOfMapNodesMap mapElemNewNodes;
4638
4639   const bool isQuadraticMesh = bool( myMesh->NbEdges(ORDER_QUADRATIC) +
4640                                      myMesh->NbFaces(ORDER_QUADRATIC) +
4641                                      myMesh->NbVolumes(ORDER_QUADRATIC) );
4642   // loop on theElems
4643   TIDSortedElemSet::iterator itElem;
4644   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4645     // check element type
4646     const SMDS_MeshElement* elem = *itElem;
4647     if ( !elem  || elem->GetType() == SMDSAbs_Volume )
4648       continue;
4649
4650     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4651     newNodesItVec.reserve( elem->NbNodes() );
4652
4653     // loop on elem nodes
4654     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4655     while ( itN->more() )
4656     {
4657       // check if a node has been already sweeped
4658       const SMDS_MeshNode* node = cast2Node( itN->next() );
4659       TNodeOfNodeListMap::iterator nIt =
4660         mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4661       list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4662       if ( listNewNodes.empty() )
4663       {
4664         // make new nodes
4665
4666         // check if we are to create medium nodes between corner ones
4667         bool needMediumNodes = false;
4668         if ( isQuadraticMesh )
4669         {
4670           SMDS_ElemIteratorPtr it = node->GetInverseElementIterator();
4671           while (it->more() && !needMediumNodes )
4672           {
4673             const SMDS_MeshElement* invElem = it->next();
4674             if ( invElem != elem && !theElems.count( invElem )) continue;
4675             needMediumNodes = ( invElem->IsQuadratic() && !invElem->IsMediumNode(node) );
4676             if ( !needMediumNodes && invElem->GetEntityType() == SMDSEntity_BiQuad_Quadrangle )
4677               needMediumNodes = true;
4678           }
4679         }
4680
4681         double coord[] = { node->X(), node->Y(), node->Z() };
4682         for ( int i = 0; i < nbsteps; i++ )
4683         {
4684           if ( needMediumNodes ) // create a medium node
4685           {
4686             double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1)/2.;
4687             double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1)/2.;
4688             double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1)/2.;
4689             if( theFlags & EXTRUSION_FLAG_SEW ) {
4690               const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4691                                                          theTolerance, theParams.myNodes);
4692               listNewNodes.push_back( newNode );
4693             }
4694             else {
4695               const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4696               myLastCreatedNodes.Append(newNode);
4697               srcNodes.Append( node );
4698               listNewNodes.push_back( newNode );
4699             }
4700           }
4701           // create a corner node
4702           coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4703           coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4704           coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4705           if( theFlags & EXTRUSION_FLAG_SEW ) {
4706             const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4707                                                        theTolerance, theParams.myNodes);
4708             listNewNodes.push_back( newNode );
4709           }
4710           else {
4711             const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4712             myLastCreatedNodes.Append(newNode);
4713             srcNodes.Append( node );
4714             listNewNodes.push_back( newNode );
4715           }
4716         }
4717       }
4718       newNodesItVec.push_back( nIt );
4719     }
4720     // make new elements
4721     sweepElement( elem, newNodesItVec, newElemsMap[elem], nbsteps, srcElems );
4722   }
4723
4724   if( theFlags & EXTRUSION_FLAG_BOUNDARY ) {
4725     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, nbsteps, srcElems );
4726   }
4727   PGroupIDs newGroupIDs;
4728   if ( theMakeGroups )
4729     newGroupIDs = generateGroups( srcNodes, srcElems, "extruded");
4730
4731   return newGroupIDs;
4732 }
4733
4734 //=======================================================================
4735 //function : ExtrusionAlongTrack
4736 //purpose  :
4737 //=======================================================================
4738 SMESH_MeshEditor::Extrusion_Error
4739 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
4740                                        SMESH_subMesh*       theTrack,
4741                                        const SMDS_MeshNode* theN1,
4742                                        const bool           theHasAngles,
4743                                        list<double>&        theAngles,
4744                                        const bool           theLinearVariation,
4745                                        const bool           theHasRefPoint,
4746                                        const gp_Pnt&        theRefPoint,
4747                                        const bool           theMakeGroups)
4748 {
4749   MESSAGE("ExtrusionAlongTrack");
4750   myLastCreatedElems.Clear();
4751   myLastCreatedNodes.Clear();
4752
4753   int aNbE;
4754   std::list<double> aPrms;
4755   TIDSortedElemSet::iterator itElem;
4756
4757   gp_XYZ aGC;
4758   TopoDS_Edge aTrackEdge;
4759   TopoDS_Vertex aV1, aV2;
4760
4761   SMDS_ElemIteratorPtr aItE;
4762   SMDS_NodeIteratorPtr aItN;
4763   SMDSAbs_ElementType aTypeE;
4764
4765   TNodeOfNodeListMap mapNewNodes;
4766
4767   // 1. Check data
4768   aNbE = theElements.size();
4769   // nothing to do
4770   if ( !aNbE )
4771     return EXTR_NO_ELEMENTS;
4772
4773   // 1.1 Track Pattern
4774   ASSERT( theTrack );
4775
4776   SMESHDS_SubMesh* pSubMeshDS = theTrack->GetSubMeshDS();
4777
4778   aItE = pSubMeshDS->GetElements();
4779   while ( aItE->more() ) {
4780     const SMDS_MeshElement* pE = aItE->next();
4781     aTypeE = pE->GetType();
4782     // Pattern must contain links only
4783     if ( aTypeE != SMDSAbs_Edge )
4784       return EXTR_PATH_NOT_EDGE;
4785   }
4786
4787   list<SMESH_MeshEditor_PathPoint> fullList;
4788
4789   const TopoDS_Shape& aS = theTrack->GetSubShape();
4790   // Sub-shape for the Pattern must be an Edge or Wire
4791   if( aS.ShapeType() == TopAbs_EDGE ) {
4792     aTrackEdge = TopoDS::Edge( aS );
4793     // the Edge must not be degenerated
4794     if ( BRep_Tool::Degenerated( aTrackEdge ) )
4795       return EXTR_BAD_PATH_SHAPE;
4796     TopExp::Vertices( aTrackEdge, aV1, aV2 );
4797     aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4798     const SMDS_MeshNode* aN1 = aItN->next();
4799     aItN = theTrack->GetFather()->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4800     const SMDS_MeshNode* aN2 = aItN->next();
4801     // starting node must be aN1 or aN2
4802     if ( !( aN1 == theN1 || aN2 == theN1 ) )
4803       return EXTR_BAD_STARTING_NODE;
4804     aItN = pSubMeshDS->GetNodes();
4805     while ( aItN->more() ) {
4806       const SMDS_MeshNode* pNode = aItN->next();
4807       const SMDS_EdgePosition* pEPos =
4808         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4809       double aT = pEPos->GetUParameter();
4810       aPrms.push_back( aT );
4811     }
4812     //Extrusion_Error err =
4813     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4814   } else if( aS.ShapeType() == TopAbs_WIRE ) {
4815     list< SMESH_subMesh* > LSM;
4816     TopTools_SequenceOfShape Edges;
4817     SMESH_subMeshIteratorPtr itSM = theTrack->getDependsOnIterator(false,true);
4818     while(itSM->more()) {
4819       SMESH_subMesh* SM = itSM->next();
4820       LSM.push_back(SM);
4821       const TopoDS_Shape& aS = SM->GetSubShape();
4822       Edges.Append(aS);
4823     }
4824     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4825     int startNid = theN1->GetID();
4826     TColStd_MapOfInteger UsedNums;
4827
4828     int NbEdges = Edges.Length();
4829     int i = 1;
4830     for(; i<=NbEdges; i++) {
4831       int k = 0;
4832       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4833       for(; itLSM!=LSM.end(); itLSM++) {
4834         k++;
4835         if(UsedNums.Contains(k)) continue;
4836         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4837         SMESH_subMesh* locTrack = *itLSM;
4838         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4839         TopExp::Vertices( aTrackEdge, aV1, aV2 );
4840         aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4841         const SMDS_MeshNode* aN1 = aItN->next();
4842         aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4843         const SMDS_MeshNode* aN2 = aItN->next();
4844         // starting node must be aN1 or aN2
4845         if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4846         // 2. Collect parameters on the track edge
4847         aPrms.clear();
4848         aItN = locMeshDS->GetNodes();
4849         while ( aItN->more() ) {
4850           const SMDS_MeshNode* pNode = aItN->next();
4851           const SMDS_EdgePosition* pEPos =
4852             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4853           double aT = pEPos->GetUParameter();
4854           aPrms.push_back( aT );
4855         }
4856         list<SMESH_MeshEditor_PathPoint> LPP;
4857         //Extrusion_Error err =
4858         MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4859         LLPPs.push_back(LPP);
4860         UsedNums.Add(k);
4861         // update startN for search following egde
4862         if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4863         else startNid = aN1->GetID();
4864         break;
4865       }
4866     }
4867     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4868     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4869     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4870     for(; itPP!=firstList.end(); itPP++) {
4871       fullList.push_back( *itPP );
4872     }
4873     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4874     fullList.pop_back();
4875     itLLPP++;
4876     for(; itLLPP!=LLPPs.end(); itLLPP++) {
4877       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4878       itPP = currList.begin();
4879       SMESH_MeshEditor_PathPoint PP2 = currList.front();
4880       gp_Dir D1 = PP1.Tangent();
4881       gp_Dir D2 = PP2.Tangent();
4882       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4883                            (D1.Z()+D2.Z())/2 ) );
4884       PP1.SetTangent(Dnew);
4885       fullList.push_back(PP1);
4886       itPP++;
4887       for(; itPP!=firstList.end(); itPP++) {
4888         fullList.push_back( *itPP );
4889       }
4890       PP1 = fullList.back();
4891       fullList.pop_back();
4892     }
4893     // if wire not closed
4894     fullList.push_back(PP1);
4895     // else ???
4896   }
4897   else {
4898     return EXTR_BAD_PATH_SHAPE;
4899   }
4900
4901   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4902                           theHasRefPoint, theRefPoint, theMakeGroups);
4903 }
4904
4905
4906 //=======================================================================
4907 //function : ExtrusionAlongTrack
4908 //purpose  :
4909 //=======================================================================
4910 SMESH_MeshEditor::Extrusion_Error
4911 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
4912                                        SMESH_Mesh*          theTrack,
4913                                        const SMDS_MeshNode* theN1,
4914                                        const bool           theHasAngles,
4915                                        list<double>&        theAngles,
4916                                        const bool           theLinearVariation,
4917                                        const bool           theHasRefPoint,
4918                                        const gp_Pnt&        theRefPoint,
4919                                        const bool           theMakeGroups)
4920 {
4921   myLastCreatedElems.Clear();
4922   myLastCreatedNodes.Clear();
4923
4924   int aNbE;
4925   std::list<double> aPrms;
4926   TIDSortedElemSet::iterator itElem;
4927
4928   gp_XYZ aGC;
4929   TopoDS_Edge aTrackEdge;
4930   TopoDS_Vertex aV1, aV2;
4931
4932   SMDS_ElemIteratorPtr aItE;
4933   SMDS_NodeIteratorPtr aItN;
4934   SMDSAbs_ElementType aTypeE;
4935
4936   TNodeOfNodeListMap mapNewNodes;
4937
4938   // 1. Check data
4939   aNbE = theElements.size();
4940   // nothing to do
4941   if ( !aNbE )
4942     return EXTR_NO_ELEMENTS;
4943
4944   // 1.1 Track Pattern
4945   ASSERT( theTrack );
4946
4947   SMESHDS_Mesh* pMeshDS = theTrack->GetMeshDS();
4948
4949   aItE = pMeshDS->elementsIterator();
4950   while ( aItE->more() ) {
4951     const SMDS_MeshElement* pE = aItE->next();
4952     aTypeE = pE->GetType();
4953     // Pattern must contain links only
4954     if ( aTypeE != SMDSAbs_Edge )
4955       return EXTR_PATH_NOT_EDGE;
4956   }
4957
4958   list<SMESH_MeshEditor_PathPoint> fullList;
4959
4960   const TopoDS_Shape& aS = theTrack->GetShapeToMesh();
4961
4962   if( aS == SMESH_Mesh::PseudoShape() ) {
4963     //Mesh without shape
4964     const SMDS_MeshNode* currentNode = NULL;
4965     const SMDS_MeshNode* prevNode = theN1;
4966     std::vector<const SMDS_MeshNode*> aNodesList;
4967     aNodesList.push_back(theN1);
4968     int nbEdges = 0, conn=0;
4969     const SMDS_MeshElement* prevElem = NULL;
4970     const SMDS_MeshElement* currentElem = NULL;
4971     int totalNbEdges = theTrack->NbEdges();
4972     SMDS_ElemIteratorPtr nIt;
4973
4974     //check start node
4975     if( !theTrack->GetMeshDS()->Contains(theN1) ) {
4976       return EXTR_BAD_STARTING_NODE;
4977     }
4978
4979     conn = nbEdgeConnectivity(theN1);
4980     if(conn > 2)
4981       return EXTR_PATH_NOT_EDGE;
4982
4983     aItE = theN1->GetInverseElementIterator();
4984     prevElem = aItE->next();
4985     currentElem = prevElem;
4986     //Get all nodes
4987     if(totalNbEdges == 1 ) {
4988       nIt = currentElem->nodesIterator();
4989       currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
4990       if(currentNode == prevNode)
4991         currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
4992       aNodesList.push_back(currentNode);
4993     } else {
4994       nIt = currentElem->nodesIterator();
4995       while( nIt->more() ) {
4996         currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
4997         if(currentNode == prevNode)
4998           currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
4999         aNodesList.push_back(currentNode);
5000
5001         //case of the closed mesh
5002         if(currentNode == theN1) {
5003           nbEdges++;
5004           break;
5005         }
5006
5007         conn = nbEdgeConnectivity(currentNode);
5008         if(conn > 2) {
5009           return EXTR_PATH_NOT_EDGE;
5010         }else if( conn == 1 && nbEdges > 0 ) {
5011           //End of the path
5012           nbEdges++;
5013           break;
5014         }else {
5015           prevNode = currentNode;
5016           aItE = currentNode->GetInverseElementIterator();
5017           currentElem = aItE->next();
5018           if( currentElem  == prevElem)
5019             currentElem = aItE->next();
5020           nIt = currentElem->nodesIterator();
5021           prevElem = currentElem;
5022           nbEdges++;
5023         }
5024       }
5025     }
5026
5027     if(nbEdges != totalNbEdges)
5028       return EXTR_PATH_NOT_EDGE;
5029
5030     TopTools_SequenceOfShape Edges;
5031     double x1,x2,y1,y2,z1,z2;
5032     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
5033     int startNid = theN1->GetID();
5034     for(int i = 1; i < aNodesList.size(); i++) {
5035       x1 = aNodesList[i-1]->X();x2 = aNodesList[i]->X();
5036       y1 = aNodesList[i-1]->Y();y2 = aNodesList[i]->Y();
5037       z1 = aNodesList[i-1]->Z();z2 = aNodesList[i]->Z();
5038       TopoDS_Edge e = BRepBuilderAPI_MakeEdge(gp_Pnt(x1,y1,z1),gp_Pnt(x2,y2,z2));
5039       list<SMESH_MeshEditor_PathPoint> LPP;
5040       aPrms.clear();
5041       MakeEdgePathPoints(aPrms, e, (aNodesList[i-1]->GetID()==startNid), LPP);
5042       LLPPs.push_back(LPP);
5043       if( aNodesList[i-1]->GetID() == startNid ) startNid = aNodesList[i]->GetID();
5044       else startNid = aNodesList[i-1]->GetID();
5045
5046     }
5047
5048     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
5049     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
5050     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
5051     for(; itPP!=firstList.end(); itPP++) {
5052       fullList.push_back( *itPP );
5053     }
5054
5055     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
5056     SMESH_MeshEditor_PathPoint PP2;
5057     fullList.pop_back();
5058     itLLPP++;
5059     for(; itLLPP!=LLPPs.end(); itLLPP++) {
5060       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
5061       itPP = currList.begin();
5062       PP2 = currList.front();
5063       gp_Dir D1 = PP1.Tangent();
5064       gp_Dir D2 = PP2.Tangent();
5065       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
5066                            (D1.Z()+D2.Z())/2 ) );
5067       PP1.SetTangent(Dnew);
5068       fullList.push_back(PP1);
5069       itPP++;
5070       for(; itPP!=currList.end(); itPP++) {
5071         fullList.push_back( *itPP );
5072       }
5073       PP1 = fullList.back();
5074       fullList.pop_back();
5075     }
5076     fullList.push_back(PP1);
5077
5078   } // Sub-shape for the Pattern must be an Edge or Wire
5079   else if( aS.ShapeType() == TopAbs_EDGE ) {
5080     aTrackEdge = TopoDS::Edge( aS );
5081     // the Edge must not be degenerated
5082     if ( BRep_Tool::Degenerated( aTrackEdge ) )
5083       return EXTR_BAD_PATH_SHAPE;
5084     TopExp::Vertices( aTrackEdge, aV1, aV2 );
5085     aItN = theTrack->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
5086     const SMDS_MeshNode* aN1 = aItN->next();
5087     aItN = theTrack->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
5088     const SMDS_MeshNode* aN2 = aItN->next();
5089     // starting node must be aN1 or aN2
5090     if ( !( aN1 == theN1 || aN2 == theN1 ) )
5091       return EXTR_BAD_STARTING_NODE;
5092     aItN = pMeshDS->nodesIterator();
5093     while ( aItN->more() ) {
5094       const SMDS_MeshNode* pNode = aItN->next();
5095       if( pNode==aN1 || pNode==aN2 ) continue;
5096       const SMDS_EdgePosition* pEPos =
5097         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
5098       double aT = pEPos->GetUParameter();
5099       aPrms.push_back( aT );
5100     }
5101     //Extrusion_Error err =
5102     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
5103   }
5104   else if( aS.ShapeType() == TopAbs_WIRE ) {
5105     list< SMESH_subMesh* > LSM;
5106     TopTools_SequenceOfShape Edges;
5107     TopExp_Explorer eExp(aS, TopAbs_EDGE);
5108     for(; eExp.More(); eExp.Next()) {
5109       TopoDS_Edge E = TopoDS::Edge( eExp.Current() );
5110       if( BRep_Tool::Degenerated(E) ) continue;
5111       SMESH_subMesh* SM = theTrack->GetSubMesh(E);
5112       if(SM) {
5113         LSM.push_back(SM);
5114         Edges.Append(E);
5115       }
5116     }
5117     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
5118     int startNid = theN1->GetID();
5119     TColStd_MapOfInteger UsedNums;
5120     int NbEdges = Edges.Length();
5121     int i = 1;
5122     for(; i<=NbEdges; i++) {
5123       int k = 0;
5124       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
5125       for(; itLSM!=LSM.end(); itLSM++) {
5126         k++;
5127         if(UsedNums.Contains(k)) continue;
5128         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
5129         SMESH_subMesh* locTrack = *itLSM;
5130         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
5131         TopExp::Vertices( aTrackEdge, aV1, aV2 );
5132         aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
5133         const SMDS_MeshNode* aN1 = aItN->next();
5134         aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
5135         const SMDS_MeshNode* aN2 = aItN->next();
5136         // starting node must be aN1 or aN2
5137         if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
5138         // 2. Collect parameters on the track edge
5139         aPrms.clear();
5140         aItN = locMeshDS->GetNodes();
5141         while ( aItN->more() ) {
5142           const SMDS_MeshNode* pNode = aItN->next();
5143           const SMDS_EdgePosition* pEPos =
5144             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
5145           double aT = pEPos->GetUParameter();
5146           aPrms.push_back( aT );
5147         }
5148         list<SMESH_MeshEditor_PathPoint> LPP;
5149         //Extrusion_Error err =
5150         MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
5151         LLPPs.push_back(LPP);
5152         UsedNums.Add(k);
5153         // update startN for search following egde
5154         if( aN1->GetID() == startNid ) startNid = aN2->GetID();
5155         else startNid = aN1->GetID();
5156         break;
5157       }
5158     }
5159     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
5160     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
5161     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
5162     for(; itPP!=firstList.end(); itPP++) {
5163       fullList.push_back( *itPP );
5164     }
5165     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
5166     fullList.pop_back();
5167     itLLPP++;
5168     for(; itLLPP!=LLPPs.end(); itLLPP++) {
5169       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
5170       itPP = currList.begin();
5171       SMESH_MeshEditor_PathPoint PP2 = currList.front();
5172       gp_Dir D1 = PP1.Tangent();
5173       gp_Dir D2 = PP2.Tangent();
5174       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
5175                            (D1.Z()+D2.Z())/2 ) );
5176       PP1.SetTangent(Dnew);
5177       fullList.push_back(PP1);
5178       itPP++;
5179       for(; itPP!=currList.end(); itPP++) {
5180         fullList.push_back( *itPP );
5181       }
5182       PP1 = fullList.back();
5183       fullList.pop_back();
5184     }
5185     // if wire not closed
5186     fullList.push_back(PP1);
5187     // else ???
5188   }
5189   else {
5190     return EXTR_BAD_PATH_SHAPE;
5191   }
5192
5193   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
5194                           theHasRefPoint, theRefPoint, theMakeGroups);
5195 }
5196
5197
5198 //=======================================================================
5199 //function : MakeEdgePathPoints
5200 //purpose  : auxilary for ExtrusionAlongTrack
5201 //=======================================================================
5202 SMESH_MeshEditor::Extrusion_Error
5203 SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>& aPrms,
5204                                      const TopoDS_Edge& aTrackEdge,
5205                                      bool FirstIsStart,
5206                                      list<SMESH_MeshEditor_PathPoint>& LPP)
5207 {
5208   Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2;
5209   aTolVec=1.e-7;
5210   aTolVec2=aTolVec*aTolVec;
5211   double aT1, aT2;
5212   TopoDS_Vertex aV1, aV2;
5213   TopExp::Vertices( aTrackEdge, aV1, aV2 );
5214   aT1=BRep_Tool::Parameter( aV1, aTrackEdge );
5215   aT2=BRep_Tool::Parameter( aV2, aTrackEdge );
5216   // 2. Collect parameters on the track edge
5217   aPrms.push_front( aT1 );
5218   aPrms.push_back( aT2 );
5219   // sort parameters
5220   aPrms.sort();
5221   if( FirstIsStart ) {
5222     if ( aT1 > aT2 ) {
5223       aPrms.reverse();
5224     }
5225   }
5226   else {
5227     if ( aT2 > aT1 ) {
5228       aPrms.reverse();
5229     }
5230   }
5231   // 3. Path Points
5232   SMESH_MeshEditor_PathPoint aPP;
5233   Handle(Geom_Curve) aC3D = BRep_Tool::Curve( aTrackEdge, aTx1, aTx2 );
5234   std::list<double>::iterator aItD = aPrms.begin();
5235   for(; aItD != aPrms.end(); ++aItD) {
5236     double aT = *aItD;
5237     gp_Pnt aP3D;
5238     gp_Vec aVec;
5239     aC3D->D1( aT, aP3D, aVec );
5240     aL2 = aVec.SquareMagnitude();
5241     if ( aL2 < aTolVec2 )
5242       return EXTR_CANT_GET_TANGENT;
5243     gp_Dir aTgt( aVec );
5244     aPP.SetPnt( aP3D );
5245     aPP.SetTangent( aTgt );
5246     aPP.SetParameter( aT );
5247     LPP.push_back(aPP);
5248   }
5249   return EXTR_OK;
5250 }
5251
5252
5253 //=======================================================================
5254 //function : MakeExtrElements
5255 //purpose  : auxilary for ExtrusionAlongTrack
5256 //=======================================================================
5257 SMESH_MeshEditor::Extrusion_Error
5258 SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet&  theElements,
5259                                    list<SMESH_MeshEditor_PathPoint>& fullList,
5260                                    const bool theHasAngles,
5261                                    list<double>& theAngles,
5262                                    const bool theLinearVariation,
5263                                    const bool theHasRefPoint,
5264                                    const gp_Pnt& theRefPoint,
5265                                    const bool theMakeGroups)
5266 {
5267   MESSAGE("MakeExtrElements");
5268   //cout<<"MakeExtrElements  fullList.size() = "<<fullList.size()<<endl;
5269   int aNbTP = fullList.size();
5270   vector<SMESH_MeshEditor_PathPoint> aPPs(aNbTP);
5271   // Angles
5272   if( theHasAngles && theAngles.size()>0 && theLinearVariation ) {
5273     LinearAngleVariation(aNbTP-1, theAngles);
5274   }
5275   vector<double> aAngles( aNbTP );
5276   int j = 0;
5277   for(; j<aNbTP; ++j) {
5278     aAngles[j] = 0.;
5279   }
5280   if ( theHasAngles ) {
5281     double anAngle;;
5282     std::list<double>::iterator aItD = theAngles.begin();
5283     for ( j=1; (aItD != theAngles.end()) && (j<aNbTP); ++aItD, ++j ) {
5284       anAngle = *aItD;
5285       aAngles[j] = anAngle;
5286     }
5287   }
5288   // fill vector of path points with angles
5289   //aPPs.resize(fullList.size());
5290   j = -1;
5291   list<SMESH_MeshEditor_PathPoint>::iterator itPP = fullList.begin();
5292   for(; itPP!=fullList.end(); itPP++) {
5293     j++;
5294     SMESH_MeshEditor_PathPoint PP = *itPP;
5295     PP.SetAngle(aAngles[j]);
5296     aPPs[j] = PP;
5297   }
5298
5299   TNodeOfNodeListMap mapNewNodes;
5300   TElemOfVecOfNnlmiMap mapElemNewNodes;
5301   TElemOfElemListMap newElemsMap;
5302   TIDSortedElemSet::iterator itElem;
5303   double aX, aY, aZ;
5304   int aNb;
5305   SMDSAbs_ElementType aTypeE;
5306   // source elements for each generated one
5307   SMESH_SequenceOfElemPtr srcElems, srcNodes;
5308
5309   // 3. Center of rotation aV0
5310   gp_Pnt aV0 = theRefPoint;
5311   gp_XYZ aGC;
5312   if ( !theHasRefPoint ) {
5313     aNb = 0;
5314     aGC.SetCoord( 0.,0.,0. );
5315
5316     itElem = theElements.begin();
5317     for ( ; itElem != theElements.end(); itElem++ ) {
5318       const SMDS_MeshElement* elem = *itElem;
5319
5320       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5321       while ( itN->more() ) {
5322         const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( itN->next() );
5323         aX = node->X();
5324         aY = node->Y();
5325         aZ = node->Z();
5326
5327         if ( mapNewNodes.find( node ) == mapNewNodes.end() ) {
5328           list<const SMDS_MeshNode*> aLNx;
5329           mapNewNodes[node] = aLNx;
5330           //
5331           gp_XYZ aXYZ( aX, aY, aZ );
5332           aGC += aXYZ;
5333           ++aNb;
5334         }
5335       }
5336     }
5337     aGC /= aNb;
5338     aV0.SetXYZ( aGC );
5339   } // if (!theHasRefPoint) {
5340   mapNewNodes.clear();
5341
5342   // 4. Processing the elements
5343   SMESHDS_Mesh* aMesh = GetMeshDS();
5344
5345   for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) {
5346     // check element type
5347     const SMDS_MeshElement* elem = *itElem;
5348     aTypeE = elem->GetType();
5349     if ( !elem || ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) )
5350       continue;
5351
5352     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
5353     newNodesItVec.reserve( elem->NbNodes() );
5354
5355     // loop on elem nodes
5356     int nodeIndex = -1;
5357     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5358     while ( itN->more() )
5359     {
5360       ++nodeIndex;
5361       // check if a node has been already processed
5362       const SMDS_MeshNode* node =
5363         static_cast<const SMDS_MeshNode*>( itN->next() );
5364       TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
5365       if ( nIt == mapNewNodes.end() ) {
5366         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
5367         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
5368
5369         // make new nodes
5370         aX = node->X();  aY = node->Y(); aZ = node->Z();
5371
5372         Standard_Real aAngle1x, aAngleT1T0, aTolAng;
5373         gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
5374         gp_Ax1 anAx1, anAxT1T0;
5375         gp_Dir aDT1x, aDT0x, aDT1T0;
5376
5377         aTolAng=1.e-4;
5378
5379         aV0x = aV0;
5380         aPN0.SetCoord(aX, aY, aZ);
5381
5382         const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
5383         aP0x = aPP0.Pnt();
5384         aDT0x= aPP0.Tangent();
5385         //cout<<"j = 0   PP: Pnt("<<aP0x.X()<<","<<aP0x.Y()<<","<<aP0x.Z()<<")"<<endl;
5386
5387         for ( j = 1; j < aNbTP; ++j ) {
5388           const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
5389           aP1x = aPP1.Pnt();
5390           aDT1x = aPP1.Tangent();
5391           aAngle1x = aPP1.Angle();
5392
5393           gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
5394           // Translation
5395           gp_Vec aV01x( aP0x, aP1x );
5396           aTrsf.SetTranslation( aV01x );
5397
5398           // traslated point
5399           aV1x = aV0x.Transformed( aTrsf );
5400           aPN1 = aPN0.Transformed( aTrsf );
5401
5402           // rotation 1 [ T1,T0 ]
5403           aAngleT1T0=-aDT1x.Angle( aDT0x );
5404           if (fabs(aAngleT1T0) > aTolAng) {
5405             aDT1T0=aDT1x^aDT0x;
5406             anAxT1T0.SetLocation( aV1x );
5407             anAxT1T0.SetDirection( aDT1T0 );
5408             aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 );
5409
5410             aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
5411           }
5412
5413           // rotation 2
5414           if ( theHasAngles ) {
5415             anAx1.SetLocation( aV1x );
5416             anAx1.SetDirection( aDT1x );
5417             aTrsfRot.SetRotation( anAx1, aAngle1x );
5418
5419             aPN1 = aPN1.Transformed( aTrsfRot );
5420           }
5421
5422           // make new node
5423           //MESSAGE("elem->IsQuadratic " << elem->IsQuadratic() << " " << elem->IsMediumNode(node));
5424           if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5425             // create additional node
5426             double x = ( aPN1.X() + aPN0.X() )/2.;
5427             double y = ( aPN1.Y() + aPN0.Y() )/2.;
5428             double z = ( aPN1.Z() + aPN0.Z() )/2.;
5429             const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z);
5430             myLastCreatedNodes.Append(newNode);
5431             srcNodes.Append( node );
5432             listNewNodes.push_back( newNode );
5433           }
5434           aX = aPN1.X();
5435           aY = aPN1.Y();
5436           aZ = aPN1.Z();
5437           const SMDS_MeshNode* newNode = aMesh->AddNode( aX, aY, aZ );
5438           myLastCreatedNodes.Append(newNode);
5439           srcNodes.Append( node );
5440           listNewNodes.push_back( newNode );
5441
5442           aPN0 = aPN1;
5443           aP0x = aP1x;
5444           aV0x = aV1x;
5445           aDT0x = aDT1x;
5446         }
5447       }
5448
5449       else {
5450         // if current elem is quadratic and current node is not medium
5451         // we have to check - may be it is needed to insert additional nodes
5452         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5453           list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
5454           if(listNewNodes.size()==aNbTP-1) {
5455             vector<const SMDS_MeshNode*> aNodes(2*(aNbTP-1));
5456             gp_XYZ P(node->X(), node->Y(), node->Z());
5457             list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin();
5458             int i;
5459             for(i=0; i<aNbTP-1; i++) {
5460               const SMDS_MeshNode* N = *it;
5461               double x = ( N->X() + P.X() )/2.;
5462               double y = ( N->Y() + P.Y() )/2.;
5463               double z = ( N->Z() + P.Z() )/2.;
5464               const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z);
5465               srcNodes.Append( node );
5466               myLastCreatedNodes.Append(newN);
5467               aNodes[2*i] = newN;
5468               aNodes[2*i+1] = N;
5469               P = gp_XYZ(N->X(),N->Y(),N->Z());
5470             }
5471             listNewNodes.clear();
5472             for(i=0; i<2*(aNbTP-1); i++) {
5473               listNewNodes.push_back(aNodes[i]);
5474             }
5475           }
5476         }
5477       }
5478
5479       newNodesItVec.push_back( nIt );
5480     }
5481     // make new elements
5482     //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem],
5483     //              newNodesItVec[0]->second.size(), myLastCreatedElems );
5484     sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems );
5485   }
5486
5487   makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElements, aNbTP-1, srcElems );
5488
5489   if ( theMakeGroups )
5490     generateGroups( srcNodes, srcElems, "extruded");
5491
5492   return EXTR_OK;
5493 }
5494
5495
5496 //=======================================================================
5497 //function : LinearAngleVariation
5498 //purpose  : auxilary for ExtrusionAlongTrack
5499 //=======================================================================
5500 void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps,
5501                                             list<double>& Angles)
5502 {
5503   int nbAngles = Angles.size();
5504   if( nbSteps > nbAngles ) {
5505     vector<double> theAngles(nbAngles);
5506     list<double>::iterator it = Angles.begin();
5507     int i = -1;
5508     for(; it!=Angles.end(); it++) {
5509       i++;
5510       theAngles[i] = (*it);
5511     }
5512     list<double> res;
5513     double rAn2St = double( nbAngles ) / double( nbSteps );
5514     double angPrev = 0, angle;
5515     for ( int iSt = 0; iSt < nbSteps; ++iSt ) {
5516       double angCur = rAn2St * ( iSt+1 );
5517       double angCurFloor  = floor( angCur );
5518       double angPrevFloor = floor( angPrev );
5519       if ( angPrevFloor == angCurFloor )
5520         angle = rAn2St * theAngles[ int( angCurFloor ) ];
5521       else {
5522         int iP = int( angPrevFloor );
5523         double angPrevCeil = ceil(angPrev);
5524         angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
5525
5526         int iC = int( angCurFloor );
5527         if ( iC < nbAngles )
5528           angle += ( angCur - angCurFloor ) * theAngles[ iC ];
5529
5530         iP = int( angPrevCeil );
5531         while ( iC-- > iP )
5532           angle += theAngles[ iC ];
5533       }
5534       res.push_back(angle);
5535       angPrev = angCur;
5536     }
5537     Angles.clear();
5538     it = res.begin();
5539     for(; it!=res.end(); it++)
5540       Angles.push_back( *it );
5541   }
5542 }
5543
5544
5545 //================================================================================
5546 /*!
5547  * \brief Move or copy theElements applying theTrsf to their nodes
5548  *  \param theElems - elements to transform, if theElems is empty then apply to all mesh nodes
5549  *  \param theTrsf - transformation to apply
5550  *  \param theCopy - if true, create translated copies of theElems
5551  *  \param theMakeGroups - if true and theCopy, create translated groups
5552  *  \param theTargetMesh - mesh to copy translated elements into
5553  *  \return SMESH_MeshEditor::PGroupIDs - list of ids of created groups
5554  */
5555 //================================================================================
5556
5557 SMESH_MeshEditor::PGroupIDs
5558 SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
5559                              const gp_Trsf&     theTrsf,
5560                              const bool         theCopy,
5561                              const bool         theMakeGroups,
5562                              SMESH_Mesh*        theTargetMesh)
5563 {
5564   myLastCreatedElems.Clear();
5565   myLastCreatedNodes.Clear();
5566
5567   bool needReverse = false;
5568   string groupPostfix;
5569   switch ( theTrsf.Form() ) {
5570   case gp_PntMirror:
5571     MESSAGE("gp_PntMirror");
5572     needReverse = true;
5573     groupPostfix = "mirrored";
5574     break;
5575   case gp_Ax1Mirror:
5576     MESSAGE("gp_Ax1Mirror");
5577     groupPostfix = "mirrored";
5578     break;
5579   case gp_Ax2Mirror:
5580     MESSAGE("gp_Ax2Mirror");
5581     needReverse = true;
5582     groupPostfix = "mirrored";
5583     break;
5584   case gp_Rotation:
5585     MESSAGE("gp_Rotation");
5586     groupPostfix = "rotated";
5587     break;
5588   case gp_Translation:
5589     MESSAGE("gp_Translation");
5590     groupPostfix = "translated";
5591     break;
5592   case gp_Scale:
5593     MESSAGE("gp_Scale");
5594     groupPostfix = "scaled";
5595     break;
5596   case gp_CompoundTrsf: // different scale by axis
5597     MESSAGE("gp_CompoundTrsf");
5598     groupPostfix = "scaled";
5599     break;
5600   default:
5601     MESSAGE("default");
5602     needReverse = false;
5603     groupPostfix = "transformed";
5604   }
5605
5606   SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5607   SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5608   SMESHDS_Mesh* aMesh    = GetMeshDS();
5609
5610
5611   // map old node to new one
5612   TNodeNodeMap nodeMap;
5613
5614   // elements sharing moved nodes; those of them which have all
5615   // nodes mirrored but are not in theElems are to be reversed
5616   TIDSortedElemSet inverseElemSet;
5617
5618   // source elements for each generated one
5619   SMESH_SequenceOfElemPtr srcElems, srcNodes;
5620
5621   // issue 021015: EDF 1578 SMESH: Free nodes are removed when translating a mesh
5622   TIDSortedElemSet orphanNode;
5623
5624   if ( theElems.empty() ) // transform the whole mesh
5625   {
5626     // add all elements
5627     SMDS_ElemIteratorPtr eIt = aMesh->elementsIterator();
5628     while ( eIt->more() ) theElems.insert( eIt->next() );
5629     // add orphan nodes
5630     SMDS_NodeIteratorPtr nIt = aMesh->nodesIterator();
5631     while ( nIt->more() )
5632     {
5633       const SMDS_MeshNode* node = nIt->next();
5634       if ( node->NbInverseElements() == 0)
5635         orphanNode.insert( node );
5636     }
5637   }
5638
5639   // loop on elements to transform nodes : first orphan nodes then elems
5640   TIDSortedElemSet::iterator itElem;
5641   TIDSortedElemSet *elements[] = {&orphanNode, &theElems };
5642   for (int i=0; i<2; i++)
5643   for ( itElem = elements[i]->begin(); itElem != elements[i]->end(); itElem++ ) {
5644     const SMDS_MeshElement* elem = *itElem;
5645     if ( !elem )
5646       continue;
5647
5648     // loop on elem nodes
5649     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5650     while ( itN->more() ) {
5651
5652       const SMDS_MeshNode* node = cast2Node( itN->next() );
5653       // check if a node has been already transformed
5654       pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5655         nodeMap.insert( make_pair ( node, node ));
5656       if ( !n2n_isnew.second )
5657         continue;
5658
5659       double coord[3];
5660       coord[0] = node->X();
5661       coord[1] = node->Y();
5662       coord[2] = node->Z();
5663       theTrsf.Transforms( coord[0], coord[1], coord[2] );
5664       if ( theTargetMesh ) {
5665         const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5666         n2n_isnew.first->second = newNode;
5667         myLastCreatedNodes.Append(newNode);
5668         srcNodes.Append( node );
5669       }
5670       else if ( theCopy ) {
5671         const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5672         n2n_isnew.first->second = newNode;
5673         myLastCreatedNodes.Append(newNode);
5674         srcNodes.Append( node );
5675       }
5676       else {
5677         aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5678         // node position on shape becomes invalid
5679         const_cast< SMDS_MeshNode* > ( node )->SetPosition
5680           ( SMDS_SpacePosition::originSpacePosition() );
5681       }
5682
5683       // keep inverse elements
5684       if ( !theCopy && !theTargetMesh && needReverse ) {
5685         SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5686         while ( invElemIt->more() ) {
5687           const SMDS_MeshElement* iel = invElemIt->next();
5688           inverseElemSet.insert( iel );
5689         }
5690       }
5691     }
5692   }
5693
5694   // either create new elements or reverse mirrored ones
5695   if ( !theCopy && !needReverse && !theTargetMesh )
5696     return PGroupIDs();
5697
5698   TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5699   for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5700     theElems.insert( *invElemIt );
5701
5702   // Replicate or reverse elements
5703
5704   std::vector<int> iForw;
5705   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5706   {
5707     const SMDS_MeshElement* elem = *itElem;
5708     if ( !elem ) continue;
5709
5710     SMDSAbs_GeometryType geomType = elem->GetGeomType();
5711     int                  nbNodes  = elem->NbNodes();
5712     if ( geomType == SMDSGeom_NONE ) continue; // node
5713
5714     switch ( geomType ) {
5715
5716     case SMDSGeom_POLYGON:  // ---------------------- polygon
5717       {
5718         vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5719         int iNode = 0;
5720         SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5721         while (itN->more()) {
5722           const SMDS_MeshNode* node =
5723             static_cast<const SMDS_MeshNode*>(itN->next());
5724           TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5725           if (nodeMapIt == nodeMap.end())
5726             break; // not all nodes transformed
5727           if (needReverse) {
5728             // reverse mirrored faces and volumes
5729             poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5730           } else {
5731             poly_nodes[iNode] = (*nodeMapIt).second;
5732           }
5733           iNode++;
5734         }
5735         if ( iNode != nbNodes )
5736           continue; // not all nodes transformed
5737
5738         if ( theTargetMesh ) {
5739           myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5740           srcElems.Append( elem );
5741         }
5742         else if ( theCopy ) {
5743           myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5744           srcElems.Append( elem );
5745         }
5746         else {
5747           aMesh->ChangePolygonNodes(elem, poly_nodes);
5748         }
5749       }
5750       break;
5751
5752     case SMDSGeom_POLYHEDRA:  // ------------------ polyhedral volume
5753       {
5754         const SMDS_VtkVolume* aPolyedre =
5755           dynamic_cast<const SMDS_VtkVolume*>( elem );
5756         if (!aPolyedre) {
5757           MESSAGE("Warning: bad volumic element");
5758           continue;
5759         }
5760
5761         vector<const SMDS_MeshNode*> poly_nodes; poly_nodes.reserve( nbNodes );
5762         vector<int> quantities; quantities.reserve( nbNodes );
5763
5764         bool allTransformed = true;
5765         int nbFaces = aPolyedre->NbFaces();
5766         for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5767           int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5768           for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5769             const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5770             TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5771             if (nodeMapIt == nodeMap.end()) {
5772               allTransformed = false; // not all nodes transformed
5773             } else {
5774               poly_nodes.push_back((*nodeMapIt).second);
5775             }
5776             if ( needReverse && allTransformed )
5777               std::reverse( poly_nodes.end() - nbFaceNodes, poly_nodes.end() );
5778           }
5779           quantities.push_back(nbFaceNodes);
5780         }
5781         if ( !allTransformed )
5782           continue; // not all nodes transformed
5783
5784         if ( theTargetMesh ) {
5785           myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5786           srcElems.Append( elem );
5787         }
5788         else if ( theCopy ) {
5789           myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5790           srcElems.Append( elem );
5791         }
5792         else {
5793           aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5794         }
5795       }
5796       break;
5797
5798     case SMDSGeom_BALL: // -------------------- Ball
5799       {
5800         if ( !theCopy && !theTargetMesh ) continue;
5801
5802         TNodeNodeMap::iterator nodeMapIt = nodeMap.find( elem->GetNode(0) );
5803         if (nodeMapIt == nodeMap.end())
5804           continue; // not all nodes transformed
5805
5806         double diameter = static_cast<const SMDS_BallElement*>(elem)->GetDiameter();
5807         if ( theTargetMesh ) {
5808           myLastCreatedElems.Append(aTgtMesh->AddBall( nodeMapIt->second, diameter ));
5809           srcElems.Append( elem );
5810         }
5811         else {
5812           myLastCreatedElems.Append(aMesh->AddBall( nodeMapIt->second, diameter ));
5813           srcElems.Append( elem );
5814         }
5815       }
5816       break;
5817
5818     default: // ----------------------- Regular elements
5819
5820       while ( iForw.size() < nbNodes ) iForw.push_back( iForw.size() );
5821       const std::vector<int>& iRev = SMDS_MeshCell::reverseSmdsOrder( elem->GetEntityType() );
5822       const std::vector<int>& i = needReverse ? iRev : iForw;
5823
5824       // find transformed nodes
5825       vector<const SMDS_MeshNode*> nodes(nbNodes);
5826       int iNode = 0;
5827       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5828       while ( itN->more() ) {
5829         const SMDS_MeshNode* node =
5830           static_cast<const SMDS_MeshNode*>( itN->next() );
5831         TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5832         if ( nodeMapIt == nodeMap.end() )
5833           break; // not all nodes transformed
5834         nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5835       }
5836       if ( iNode != nbNodes )
5837         continue; // not all nodes transformed
5838
5839       if ( theTargetMesh ) {
5840         if ( SMDS_MeshElement* copy =
5841              targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5842           myLastCreatedElems.Append( copy );
5843           srcElems.Append( elem );
5844         }
5845       }
5846       else if ( theCopy ) {
5847         if ( AddElement( nodes, elem->GetType(), elem->IsPoly() ))
5848           srcElems.Append( elem );
5849       }
5850       else {
5851         // reverse element as it was reversed by transformation
5852         if ( nbNodes > 2 )
5853           aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5854       }
5855     } // switch ( geomType )
5856
5857   } // loop on elements
5858
5859   PGroupIDs newGroupIDs;
5860
5861   if ( ( theMakeGroups && theCopy ) ||
5862        ( theMakeGroups && theTargetMesh ) )
5863     newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5864
5865   return newGroupIDs;
5866 }
5867
5868 //=======================================================================
5869 /*!
5870  * \brief Create groups of elements made during transformation
5871  * \param nodeGens - nodes making corresponding myLastCreatedNodes
5872  * \param elemGens - elements making corresponding myLastCreatedElems
5873  * \param postfix - to append to names of new groups
5874  */
5875 //=======================================================================
5876
5877 SMESH_MeshEditor::PGroupIDs
5878 SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
5879                                  const SMESH_SequenceOfElemPtr& elemGens,
5880                                  const std::string&             postfix,
5881                                  SMESH_Mesh*                    targetMesh)
5882 {
5883   PGroupIDs newGroupIDs( new list<int> );
5884   SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh();
5885
5886   // Sort existing groups by types and collect their names
5887
5888   // to store an old group and a generated new one
5889   typedef pair< SMESHDS_GroupBase*, SMESHDS_Group* > TOldNewGroup;
5890   vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
5891   vector< TOldNewGroup* > orderedOldNewGroups; // in order of old groups
5892   // group names
5893   set< string > groupNames;
5894   
5895   SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups();
5896   if ( !groupIt->more() ) return newGroupIDs;
5897
5898   int newGroupID = mesh->GetGroupIds().back()+1;
5899   while ( groupIt->more() )
5900   {
5901     SMESH_Group * group = groupIt->next();
5902     if ( !group ) continue;
5903     SMESHDS_GroupBase* groupDS = group->GetGroupDS();
5904     if ( !groupDS || groupDS->IsEmpty() ) continue;
5905     groupNames.insert( group->GetName() );
5906     groupDS->SetStoreName( group->GetName() );
5907     SMESHDS_Group* newGroup = new SMESHDS_Group( newGroupID++, mesh->GetMeshDS(),
5908                                                  groupDS->GetType() );
5909     groupsByType[ groupDS->GetType() ].push_back( make_pair( groupDS, newGroup ));
5910     orderedOldNewGroups.push_back( & groupsByType[ groupDS->GetType() ].back() );
5911   }
5912
5913   // Loop on nodes and elements to add them in new groups
5914
5915   for ( int isNodes = 0; isNodes < 2; ++isNodes )
5916   {
5917     const SMESH_SequenceOfElemPtr& gens  = isNodes ? nodeGens : elemGens;
5918     const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
5919     if ( gens.Length() != elems.Length() )
5920       throw SALOME_Exception(LOCALIZED("invalid args"));
5921
5922     // loop on created elements
5923     for (int iElem = 1; iElem <= elems.Length(); ++iElem )
5924     {
5925       const SMDS_MeshElement* sourceElem = gens( iElem );
5926       if ( !sourceElem ) {
5927         MESSAGE("generateGroups(): NULL source element");
5928         continue;
5929       }
5930       list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
5931       if ( groupsOldNew.empty() ) { // no groups of this type at all
5932         while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
5933           ++iElem; // skip all elements made by sourceElem
5934         continue;
5935       }
5936       // collect all elements made by sourceElem
5937       list< const SMDS_MeshElement* > resultElems;
5938       if ( const SMDS_MeshElement* resElem = elems( iElem ))
5939         if ( resElem != sourceElem )
5940           resultElems.push_back( resElem );
5941       while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
5942         if ( const SMDS_MeshElement* resElem = elems( ++iElem ))
5943           if ( resElem != sourceElem )
5944             resultElems.push_back( resElem );
5945
5946       // add resultElems to groups made by ones the sourceElem belongs to
5947       list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
5948       for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
5949       {
5950         SMESHDS_GroupBase* oldGroup = gOldNew->first;
5951         if ( oldGroup->Contains( sourceElem )) // sourceElem is in oldGroup
5952         {
5953           // fill in a new group
5954           SMDS_MeshGroup & newGroup = gOldNew->second->SMDSGroup();
5955           list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
5956           for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
5957             newGroup.Add( *resElemIt );
5958         }
5959       }
5960     } // loop on created elements
5961   }// loop on nodes and elements
5962
5963   // Create new SMESH_Groups from SMESHDS_Groups and remove empty SMESHDS_Groups
5964
5965   for ( size_t i = 0; i < orderedOldNewGroups.size(); ++i )
5966   {
5967     SMESHDS_GroupBase* oldGroupDS = orderedOldNewGroups[i]->first;
5968     SMESHDS_Group*     newGroupDS = orderedOldNewGroups[i]->second;
5969     if ( newGroupDS->IsEmpty() )
5970     {
5971       mesh->GetMeshDS()->RemoveGroup( newGroupDS );
5972     }
5973     else
5974     {
5975       // make a name
5976       string name = oldGroupDS->GetStoreName();
5977       if ( !targetMesh ) {
5978         name += "_";
5979         name += postfix;
5980         int nb = 1;
5981         while ( !groupNames.insert( name ).second ) // name exists
5982           name = SMESH_Comment( oldGroupDS->GetStoreName() ) << "_" << postfix << "_" << nb++;
5983       }
5984       newGroupDS->SetStoreName( name.c_str() );
5985
5986       // make a SMESH_Groups
5987       mesh->AddGroup( newGroupDS );
5988       newGroupIDs->push_back( newGroupDS->GetID() );
5989
5990       // set group type
5991       newGroupDS->SetType( newGroupDS->GetElements()->next()->GetType() );
5992     }
5993   }
5994
5995   return newGroupIDs;
5996 }
5997
5998 //================================================================================
5999 /*!
6000  * \brief Return list of group of nodes close to each other within theTolerance
6001  *        Search among theNodes or in the whole mesh if theNodes is empty using
6002  *        an Octree algorithm
6003  */
6004 //================================================================================
6005
6006 void SMESH_MeshEditor::FindCoincidentNodes (TIDSortedNodeSet &   theNodes,
6007                                             const double         theTolerance,
6008                                             TListOfListOfNodes & theGroupsOfNodes)
6009 {
6010   myLastCreatedElems.Clear();
6011   myLastCreatedNodes.Clear();
6012
6013   if ( theNodes.empty() )
6014   { // get all nodes in the mesh
6015     SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator(/*idInceasingOrder=*/true);
6016     while ( nIt->more() )
6017       theNodes.insert( theNodes.end(),nIt->next());
6018   }
6019
6020   SMESH_OctreeNode::FindCoincidentNodes ( theNodes, &theGroupsOfNodes, theTolerance);
6021 }
6022
6023
6024 //=======================================================================
6025 /*!
6026  * \brief Implementation of search for the node closest to point
6027  */
6028 //=======================================================================
6029
6030 struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
6031 {
6032   //---------------------------------------------------------------------
6033   /*!
6034    * \brief Constructor
6035    */
6036   SMESH_NodeSearcherImpl( const SMESHDS_Mesh* theMesh )
6037   {
6038     myMesh = ( SMESHDS_Mesh* ) theMesh;
6039
6040     TIDSortedNodeSet nodes;
6041     if ( theMesh ) {
6042       SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator(/*idInceasingOrder=*/true);
6043       while ( nIt->more() )
6044         nodes.insert( nodes.end(), nIt->next() );
6045     }
6046     myOctreeNode = new SMESH_OctreeNode(nodes) ;
6047
6048     // get max size of a leaf box
6049     SMESH_OctreeNode* tree = myOctreeNode;
6050     while ( !tree->isLeaf() )
6051     {
6052       SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
6053       if ( cIt->more() )
6054         tree = cIt->next();
6055     }
6056     myHalfLeafSize = tree->maxSize() / 2.;
6057   }
6058
6059   //---------------------------------------------------------------------
6060   /*!
6061    * \brief Move node and update myOctreeNode accordingly
6062    */
6063   void MoveNode( const SMDS_MeshNode* node, const gp_Pnt& toPnt )
6064   {
6065     myOctreeNode->UpdateByMoveNode( node, toPnt );
6066     myMesh->MoveNode( node, toPnt.X(), toPnt.Y(), toPnt.Z() );
6067   }
6068
6069   //---------------------------------------------------------------------
6070   /*!
6071    * \brief Do it's job
6072    */
6073   const SMDS_MeshNode* FindClosestTo( const gp_Pnt& thePnt )
6074   {
6075     map<double, const SMDS_MeshNode*> dist2Nodes;
6076     myOctreeNode->NodesAround( thePnt.Coord(), dist2Nodes, myHalfLeafSize );
6077     if ( !dist2Nodes.empty() )
6078       return dist2Nodes.begin()->second;
6079     list<const SMDS_MeshNode*> nodes;
6080     //myOctreeNode->NodesAround( &tgtNode, &nodes, myHalfLeafSize );
6081
6082     double minSqDist = DBL_MAX;
6083     if ( nodes.empty() )  // get all nodes of OctreeNode's closest to thePnt
6084     {
6085       // sort leafs by their distance from thePnt
6086       typedef map< double, SMESH_OctreeNode* > TDistTreeMap;
6087       TDistTreeMap treeMap;
6088       list< SMESH_OctreeNode* > treeList;
6089       list< SMESH_OctreeNode* >::iterator trIt;
6090       treeList.push_back( myOctreeNode );
6091
6092       gp_XYZ pointNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
6093       bool pointInside = myOctreeNode->isInside( pointNode, myHalfLeafSize );
6094       for ( trIt = treeList.begin(); trIt != treeList.end(); ++trIt)
6095       {
6096         SMESH_OctreeNode* tree = *trIt;
6097         if ( !tree->isLeaf() ) // put children to the queue
6098         {
6099           if ( pointInside && !tree->isInside( pointNode, myHalfLeafSize )) continue;
6100           SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
6101           while ( cIt->more() )
6102             treeList.push_back( cIt->next() );
6103         }
6104         else if ( tree->NbNodes() ) // put a tree to the treeMap
6105         {
6106           const Bnd_B3d& box = tree->getBox();
6107           double sqDist = thePnt.SquareDistance( 0.5 * ( box.CornerMin() + box.CornerMax() ));
6108           pair<TDistTreeMap::iterator,bool> it_in = treeMap.insert( make_pair( sqDist, tree ));
6109           if ( !it_in.second ) // not unique distance to box center
6110             treeMap.insert( it_in.first, make_pair( sqDist + 1e-13*treeMap.size(), tree ));
6111         }
6112       }
6113       // find distance after which there is no sense to check tree's
6114       double sqLimit = DBL_MAX;
6115       TDistTreeMap::iterator sqDist_tree = treeMap.begin();
6116       if ( treeMap.size() > 5 ) {
6117         SMESH_OctreeNode* closestTree = sqDist_tree->second;
6118         const Bnd_B3d& box = closestTree->getBox();
6119         double limit = sqrt( sqDist_tree->first ) + sqrt ( box.SquareExtent() );
6120         sqLimit = limit * limit;
6121       }
6122       // get all nodes from trees
6123       for ( ; sqDist_tree != treeMap.end(); ++sqDist_tree) {
6124         if ( sqDist_tree->first > sqLimit )
6125           break;
6126         SMESH_OctreeNode* tree = sqDist_tree->second;
6127         tree->NodesAround( tree->GetNodeIterator()->next(), &nodes );
6128       }
6129     }
6130     // find closest among nodes
6131     minSqDist = DBL_MAX;
6132     const SMDS_MeshNode* closestNode = 0;
6133     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
6134     for ( ; nIt != nodes.end(); ++nIt ) {
6135       double sqDist = thePnt.SquareDistance( SMESH_TNodeXYZ( *nIt ) );
6136       if ( minSqDist > sqDist ) {
6137         closestNode = *nIt;
6138         minSqDist = sqDist;
6139       }
6140     }
6141     return closestNode;
6142   }
6143
6144   //---------------------------------------------------------------------
6145   /*!
6146    * \brief Destructor
6147    */
6148   ~SMESH_NodeSearcherImpl() { delete myOctreeNode; }
6149
6150   //---------------------------------------------------------------------
6151   /*!
6152    * \brief Return the node tree
6153    */
6154   const SMESH_OctreeNode* getTree() const { return myOctreeNode; }
6155
6156 private:
6157   SMESH_OctreeNode* myOctreeNode;
6158   SMESHDS_Mesh*     myMesh;
6159   double            myHalfLeafSize; // max size of a leaf box
6160 };
6161
6162 //=======================================================================
6163 /*!
6164  * \brief Return SMESH_NodeSearcher
6165  */
6166 //=======================================================================
6167
6168 SMESH_NodeSearcher* SMESH_MeshEditor::GetNodeSearcher()
6169 {
6170   return new SMESH_NodeSearcherImpl( GetMeshDS() );
6171 }
6172
6173 // ========================================================================
6174 namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
6175 {
6176   const int MaxNbElemsInLeaf = 10; // maximal number of elements in a leaf of tree
6177   const int MaxLevel         = 7;  // maximal tree height -> nb terminal boxes: 8^7 = 2097152
6178   const double NodeRadius = 1e-9;  // to enlarge bnd box of element
6179
6180   //=======================================================================
6181   /*!
6182    * \brief Octal tree of bounding boxes of elements
6183    */
6184   //=======================================================================
6185
6186   class ElementBndBoxTree : public SMESH_Octree
6187   {
6188   public:
6189
6190     ElementBndBoxTree(const SMDS_Mesh&     mesh,
6191                       SMDSAbs_ElementType  elemType,
6192                       SMDS_ElemIteratorPtr theElemIt = SMDS_ElemIteratorPtr(),
6193                       double               tolerance = NodeRadius );
6194     void getElementsNearPoint( const gp_Pnt& point, TIDSortedElemSet& foundElems );
6195     void getElementsNearLine ( const gp_Ax1& line, TIDSortedElemSet& foundElems);
6196     void getElementsInSphere ( const gp_XYZ& center,
6197                                const double  radius, TIDSortedElemSet& foundElems);
6198     size_t getSize() { return std::max( _size, _elements.size() ); }
6199     ~ElementBndBoxTree();
6200
6201   protected:
6202     ElementBndBoxTree():_size(0) {}
6203     SMESH_Octree* allocateOctreeChild() const { return new ElementBndBoxTree; }
6204     void          buildChildrenData();
6205     Bnd_B3d*      buildRootBox();
6206   private:
6207     //!< Bounding box of element
6208     struct ElementBox : public Bnd_B3d
6209     {
6210       const SMDS_MeshElement* _element;
6211       int                     _refCount; // an ElementBox can be included in several tree branches
6212       ElementBox(const SMDS_MeshElement* elem, double tolerance);
6213     };
6214     vector< ElementBox* > _elements;
6215     size_t                _size;
6216   };
6217
6218   //================================================================================
6219   /*!
6220    * \brief ElementBndBoxTree creation
6221    */
6222   //================================================================================
6223
6224   ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, SMDS_ElemIteratorPtr theElemIt, double tolerance)
6225     :SMESH_Octree( new SMESH_Octree::Limit( MaxLevel, /*minSize=*/0. ))
6226   {
6227     int nbElems = mesh.GetMeshInfo().NbElements( elemType );
6228     _elements.reserve( nbElems );
6229
6230     SMDS_ElemIteratorPtr elemIt = theElemIt ? theElemIt : mesh.elementsIterator( elemType );
6231     while ( elemIt->more() )
6232       _elements.push_back( new ElementBox( elemIt->next(),tolerance  ));
6233
6234     compute();
6235   }
6236
6237   //================================================================================
6238   /*!
6239    * \brief Destructor
6240    */
6241   //================================================================================
6242
6243   ElementBndBoxTree::~ElementBndBoxTree()
6244   {
6245     for ( int i = 0; i < _elements.size(); ++i )
6246       if ( --_elements[i]->_refCount <= 0 )
6247         delete _elements[i];
6248   }
6249
6250   //================================================================================
6251   /*!
6252    * \brief Return the maximal box
6253    */
6254   //================================================================================
6255
6256   Bnd_B3d* ElementBndBoxTree::buildRootBox()
6257   {
6258     Bnd_B3d* box = new Bnd_B3d;
6259     for ( int i = 0; i < _elements.size(); ++i )
6260       box->Add( *_elements[i] );
6261     return box;
6262   }
6263
6264   //================================================================================
6265   /*!
6266    * \brief Redistrubute element boxes among children
6267    */
6268   //================================================================================
6269
6270   void ElementBndBoxTree::buildChildrenData()
6271   {
6272     for ( int i = 0; i < _elements.size(); ++i )
6273     {
6274       for (int j = 0; j < 8; j++)
6275       {
6276         if ( !_elements[i]->IsOut( myChildren[j]->getBox() ))
6277         {
6278           _elements[i]->_refCount++;
6279           ((ElementBndBoxTree*)myChildren[j])->_elements.push_back( _elements[i]);
6280         }
6281       }
6282       _elements[i]->_refCount--;
6283     }
6284     _size = _elements.size();
6285     SMESHUtils::FreeVector( _elements ); // = _elements.clear() + free memory
6286
6287     for (int j = 0; j < 8; j++)
6288     {
6289       ElementBndBoxTree* child = static_cast<ElementBndBoxTree*>( myChildren[j]);
6290       if ( child->_elements.size() <= MaxNbElemsInLeaf )
6291         child->myIsLeaf = true;
6292
6293       if ( child->_elements.capacity() - child->_elements.size() > 1000 )
6294         SMESHUtils::CompactVector( child->_elements );
6295     }
6296   }
6297
6298   //================================================================================
6299   /*!
6300    * \brief Return elements which can include the point
6301    */
6302   //================================================================================
6303
6304   void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt&     point,
6305                                                 TIDSortedElemSet& foundElems)
6306   {
6307     if ( getBox().IsOut( point.XYZ() ))
6308       return;
6309
6310     if ( isLeaf() )
6311     {
6312       for ( int i = 0; i < _elements.size(); ++i )
6313         if ( !_elements[i]->IsOut( point.XYZ() ))
6314           foundElems.insert( _elements[i]->_element );
6315     }
6316     else
6317     {
6318       for (int i = 0; i < 8; i++)
6319         ((ElementBndBoxTree*) myChildren[i])->getElementsNearPoint( point, foundElems );
6320     }
6321   }
6322
6323   //================================================================================
6324   /*!
6325    * \brief Return elements which can be intersected by the line
6326    */
6327   //================================================================================
6328
6329   void ElementBndBoxTree::getElementsNearLine( const gp_Ax1&     line,
6330                                                TIDSortedElemSet& foundElems)
6331   {
6332     if ( getBox().IsOut( line ))
6333       return;
6334
6335     if ( isLeaf() )
6336     {
6337       for ( int i = 0; i < _elements.size(); ++i )
6338         if ( !_elements[i]->IsOut( line ))
6339           foundElems.insert( _elements[i]->_element );
6340     }
6341     else
6342     {
6343       for (int i = 0; i < 8; i++)
6344         ((ElementBndBoxTree*) myChildren[i])->getElementsNearLine( line, foundElems );
6345     }
6346   }
6347
6348   //================================================================================
6349   /*!
6350    * \brief Return elements from leaves intersecting the sphere
6351    */
6352   //================================================================================
6353
6354   void ElementBndBoxTree::getElementsInSphere ( const gp_XYZ&     center,
6355                                                 const double      radius,
6356                                                 TIDSortedElemSet& foundElems)
6357   {
6358     if ( getBox().IsOut( center, radius ))
6359       return;
6360
6361     if ( isLeaf() )
6362     {
6363       for ( int i = 0; i < _elements.size(); ++i )
6364         if ( !_elements[i]->IsOut( center, radius ))
6365           foundElems.insert( _elements[i]->_element );
6366     }
6367     else
6368     {
6369       for (int i = 0; i < 8; i++)
6370         ((ElementBndBoxTree*) myChildren[i])->getElementsInSphere( center, radius, foundElems );
6371     }
6372   }
6373
6374   //================================================================================
6375   /*!
6376    * \brief Construct the element box
6377    */
6378   //================================================================================
6379
6380   ElementBndBoxTree::ElementBox::ElementBox(const SMDS_MeshElement* elem, double tolerance)
6381   {
6382     _element  = elem;
6383     _refCount = 1;
6384     SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
6385     while ( nIt->more() )
6386       Add( SMESH_TNodeXYZ( nIt->next() ));
6387     Enlarge( tolerance );
6388   }
6389
6390 } // namespace
6391
6392 //=======================================================================
6393 /*!
6394  * \brief Implementation of search for the elements by point and
6395  *        of classification of point in 2D mesh
6396  */
6397 //=======================================================================
6398
6399 struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher
6400 {
6401   SMESHDS_Mesh*                _mesh;
6402   SMDS_ElemIteratorPtr         _meshPartIt;
6403   ElementBndBoxTree*           _ebbTree;
6404   SMESH_NodeSearcherImpl*      _nodeSearcher;
6405   SMDSAbs_ElementType          _elementType;
6406   double                       _tolerance;
6407   bool                         _outerFacesFound;
6408   set<const SMDS_MeshElement*> _outerFaces; // empty means "no internal faces at all"
6409
6410   SMESH_ElementSearcherImpl( SMESHDS_Mesh& mesh, SMDS_ElemIteratorPtr elemIt=SMDS_ElemIteratorPtr())
6411     : _mesh(&mesh),_meshPartIt(elemIt),_ebbTree(0),_nodeSearcher(0),_tolerance(-1),_outerFacesFound(false) {}
6412   ~SMESH_ElementSearcherImpl()
6413   {
6414     if ( _ebbTree )      delete _ebbTree;      _ebbTree      = 0;
6415     if ( _nodeSearcher ) delete _nodeSearcher; _nodeSearcher = 0;
6416   }
6417   virtual int FindElementsByPoint(const gp_Pnt&                      point,
6418                                   SMDSAbs_ElementType                type,
6419                                   vector< const SMDS_MeshElement* >& foundElements);
6420   virtual TopAbs_State GetPointState(const gp_Pnt& point);
6421   virtual const SMDS_MeshElement* FindClosestTo( const gp_Pnt&       point,
6422                                                  SMDSAbs_ElementType type );
6423
6424   void GetElementsNearLine( const gp_Ax1&                      line,
6425                             SMDSAbs_ElementType                type,
6426                             vector< const SMDS_MeshElement* >& foundElems);
6427   double getTolerance();
6428   bool getIntersParamOnLine(const gp_Lin& line, const SMDS_MeshElement* face,
6429                             const double tolerance, double & param);
6430   void findOuterBoundary(const SMDS_MeshElement* anyOuterFace);
6431   bool isOuterBoundary(const SMDS_MeshElement* face) const
6432   {
6433     return _outerFaces.empty() || _outerFaces.count(face);
6434   }
6435   struct TInters //!< data of intersection of the line and the mesh face (used in GetPointState())
6436   {
6437     const SMDS_MeshElement* _face;
6438     gp_Vec                  _faceNorm;
6439     bool                    _coincides; //!< the line lays in face plane
6440     TInters(const SMDS_MeshElement* face, const gp_Vec& faceNorm, bool coinc=false)
6441       : _face(face), _faceNorm( faceNorm ), _coincides( coinc ) {}
6442   };
6443   struct TFaceLink //!< link and faces sharing it (used in findOuterBoundary())
6444   {
6445     SMESH_TLink      _link;
6446     TIDSortedElemSet _faces;
6447     TFaceLink( const SMDS_MeshNode* n1, const SMDS_MeshNode* n2, const SMDS_MeshElement* face)
6448       : _link( n1, n2 ), _faces( &face, &face + 1) {}
6449   };
6450 };
6451
6452 ostream& operator<< (ostream& out, const SMESH_ElementSearcherImpl::TInters& i)
6453 {
6454   return out << "TInters(face=" << ( i._face ? i._face->GetID() : 0)
6455              << ", _coincides="<<i._coincides << ")";
6456 }
6457
6458 //=======================================================================
6459 /*!
6460  * \brief define tolerance for search
6461  */
6462 //=======================================================================
6463
6464 double SMESH_ElementSearcherImpl::getTolerance()
6465 {
6466   if ( _tolerance < 0 )
6467   {
6468     const SMDS_MeshInfo& meshInfo = _mesh->GetMeshInfo();
6469
6470     _tolerance = 0;
6471     if ( _nodeSearcher && meshInfo.NbNodes() > 1 )
6472     {
6473       double boxSize = _nodeSearcher->getTree()->maxSize();
6474       _tolerance = 1e-8 * boxSize/* / meshInfo.NbNodes()*/;
6475     }
6476     else if ( _ebbTree && meshInfo.NbElements() > 0 )
6477     {
6478       double boxSize = _ebbTree->maxSize();
6479       _tolerance = 1e-8 * boxSize/* / meshInfo.NbElements()*/;
6480     }
6481     if ( _tolerance == 0 )
6482     {
6483       // define tolerance by size of a most complex element
6484       int complexType = SMDSAbs_Volume;
6485       while ( complexType > SMDSAbs_All &&
6486               meshInfo.NbElements( SMDSAbs_ElementType( complexType )) < 1 )
6487         --complexType;
6488       if ( complexType == SMDSAbs_All ) return 0; // empty mesh
6489       double elemSize;
6490       if ( complexType == int( SMDSAbs_Node ))
6491       {
6492         SMDS_NodeIteratorPtr nodeIt = _mesh->nodesIterator();
6493         elemSize = 1;
6494         if ( meshInfo.NbNodes() > 2 )
6495           elemSize = SMESH_TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() );
6496       }
6497       else
6498       {
6499         SMDS_ElemIteratorPtr elemIt =
6500             _mesh->elementsIterator( SMDSAbs_ElementType( complexType ));
6501         const SMDS_MeshElement* elem = elemIt->next();
6502         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
6503         SMESH_TNodeXYZ n1( cast2Node( nodeIt->next() ));
6504         elemSize = 0;
6505         while ( nodeIt->more() )
6506         {
6507           double dist = n1.Distance( cast2Node( nodeIt->next() ));
6508           elemSize = max( dist, elemSize );
6509         }
6510       }
6511       _tolerance = 1e-4 * elemSize;
6512     }
6513   }
6514   return _tolerance;
6515 }
6516
6517 //================================================================================
6518 /*!
6519  * \brief Find intersection of the line and an edge of face and return parameter on line
6520  */
6521 //================================================================================
6522
6523 bool SMESH_ElementSearcherImpl::getIntersParamOnLine(const gp_Lin&           line,
6524                                                      const SMDS_MeshElement* face,
6525                                                      const double            tol,
6526                                                      double &                param)
6527 {
6528   int nbInts = 0;
6529   param = 0;
6530
6531   GeomAPI_ExtremaCurveCurve anExtCC;
6532   Handle(Geom_Curve) lineCurve = new Geom_Line( line );
6533
6534   int nbNodes = face->IsQuadratic() ? face->NbNodes()/2 : face->NbNodes();
6535   for ( int i = 0; i < nbNodes && nbInts < 2; ++i )
6536   {
6537     GC_MakeSegment edge( SMESH_TNodeXYZ( face->GetNode( i )),
6538                          SMESH_TNodeXYZ( face->GetNode( (i+1)%nbNodes) ));
6539     anExtCC.Init( lineCurve, edge);
6540     if ( anExtCC.NbExtrema() > 0 && anExtCC.LowerDistance() <= tol)
6541     {
6542       Quantity_Parameter pl, pe;
6543       anExtCC.LowerDistanceParameters( pl, pe );
6544       param += pl;
6545       if ( ++nbInts == 2 )
6546         break;
6547     }
6548   }
6549   if ( nbInts > 0 ) param /= nbInts;
6550   return nbInts > 0;
6551 }
6552 //================================================================================
6553 /*!
6554  * \brief Find all faces belonging to the outer boundary of mesh
6555  */
6556 //================================================================================
6557
6558 void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerFace)
6559 {
6560   if ( _outerFacesFound ) return;
6561
6562   // Collect all outer faces by passing from one outer face to another via their links
6563   // and BTW find out if there are internal faces at all.
6564
6565   // checked links and links where outer boundary meets internal one
6566   set< SMESH_TLink > visitedLinks, seamLinks;
6567
6568   // links to treat with already visited faces sharing them
6569   list < TFaceLink > startLinks;
6570
6571   // load startLinks with the first outerFace
6572   startLinks.push_back( TFaceLink( outerFace->GetNode(0), outerFace->GetNode(1), outerFace));
6573   _outerFaces.insert( outerFace );
6574
6575   TIDSortedElemSet emptySet;
6576   while ( !startLinks.empty() )
6577   {
6578     const SMESH_TLink& link  = startLinks.front()._link;
6579     TIDSortedElemSet&  faces = startLinks.front()._faces;
6580
6581     outerFace = *faces.begin();
6582     // find other faces sharing the link
6583     const SMDS_MeshElement* f;
6584     while (( f = SMESH_MeshEditor::FindFaceInSet(link.node1(), link.node2(), emptySet, faces )))
6585       faces.insert( f );
6586
6587     // select another outer face among the found
6588     const SMDS_MeshElement* outerFace2 = 0;
6589     if ( faces.size() == 2 )
6590     {
6591       outerFace2 = (outerFace == *faces.begin() ? *faces.rbegin() : *faces.begin());
6592     }
6593     else if ( faces.size() > 2 )
6594     {
6595       seamLinks.insert( link );
6596
6597       // link direction within the outerFace
6598       gp_Vec n1n2( SMESH_TNodeXYZ( link.node1()),
6599                    SMESH_TNodeXYZ( link.node2()));
6600       int i1 = outerFace->GetNodeIndex( link.node1() );
6601       int i2 = outerFace->GetNodeIndex( link.node2() );
6602       bool rev = ( abs(i2-i1) == 1 ? i1 > i2 : i2 > i1 );
6603       if ( rev ) n1n2.Reverse();
6604       // outerFace normal
6605       gp_XYZ ofNorm, fNorm;
6606       if ( SMESH_Algo::FaceNormal( outerFace, ofNorm, /*normalized=*/false ))
6607       {
6608         // direction from the link inside outerFace
6609         gp_Vec dirInOF = gp_Vec( ofNorm ) ^ n1n2;
6610         // sort all other faces by angle with the dirInOF
6611         map< double, const SMDS_MeshElement* > angle2Face;
6612         set< const SMDS_MeshElement*, TIDCompare >::const_iterator face = faces.begin();
6613         for ( ; face != faces.end(); ++face )
6614         {
6615           if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false ))
6616             continue;
6617           gp_Vec dirInF = gp_Vec( fNorm ) ^ n1n2;
6618           double angle = dirInOF.AngleWithRef( dirInF, n1n2 );
6619           if ( angle < 0 ) angle += 2. * M_PI;
6620           angle2Face.insert( make_pair( angle, *face ));
6621         }
6622         if ( !angle2Face.empty() )
6623           outerFace2 = angle2Face.begin()->second;
6624       }
6625     }
6626     // store the found outer face and add its links to continue seaching from
6627     if ( outerFace2 )
6628     {
6629       _outerFaces.insert( outerFace );
6630       int nbNodes = outerFace2->NbNodes()/( outerFace2->IsQuadratic() ? 2 : 1 );
6631       for ( int i = 0; i < nbNodes; ++i )
6632       {
6633         SMESH_TLink link2( outerFace2->GetNode(i), outerFace2->GetNode((i+1)%nbNodes));
6634         if ( visitedLinks.insert( link2 ).second )
6635           startLinks.push_back( TFaceLink( link2.node1(), link2.node2(), outerFace2 ));
6636       }
6637     }
6638     startLinks.pop_front();
6639   }
6640   _outerFacesFound = true;
6641
6642   if ( !seamLinks.empty() )
6643   {
6644     // There are internal boundaries touching the outher one,
6645     // find all faces of internal boundaries in order to find
6646     // faces of boundaries of holes, if any.
6647
6648   }
6649   else
6650   {
6651     _outerFaces.clear();
6652   }
6653 }
6654
6655 //=======================================================================
6656 /*!
6657  * \brief Find elements of given type where the given point is IN or ON.
6658  *        Returns nb of found elements and elements them-selves.
6659  *
6660  * 'ALL' type means elements of any type excluding nodes, balls and 0D elements 
6661  */
6662 //=======================================================================
6663
6664 int SMESH_ElementSearcherImpl::
6665 FindElementsByPoint(const gp_Pnt&                      point,
6666                     SMDSAbs_ElementType                type,
6667                     vector< const SMDS_MeshElement* >& foundElements)
6668 {
6669   foundElements.clear();
6670
6671   double tolerance = getTolerance();
6672
6673   // =================================================================================
6674   if ( type == SMDSAbs_Node || type == SMDSAbs_0DElement || type == SMDSAbs_Ball)
6675   {
6676     if ( !_nodeSearcher )
6677       _nodeSearcher = new SMESH_NodeSearcherImpl( _mesh );
6678
6679     const SMDS_MeshNode* closeNode = _nodeSearcher->FindClosestTo( point );
6680     if ( !closeNode ) return foundElements.size();
6681
6682     if ( point.Distance( SMESH_TNodeXYZ( closeNode )) > tolerance )
6683       return foundElements.size(); // to far from any node
6684
6685     if ( type == SMDSAbs_Node )
6686     {
6687       foundElements.push_back( closeNode );
6688     }
6689     else
6690     {
6691       SMDS_ElemIteratorPtr elemIt = closeNode->GetInverseElementIterator( type );
6692       while ( elemIt->more() )
6693         foundElements.push_back( elemIt->next() );
6694     }
6695   }
6696   // =================================================================================
6697   else // elements more complex than 0D
6698   {
6699     if ( !_ebbTree || _elementType != type )
6700     {
6701       if ( _ebbTree ) delete _ebbTree;
6702       _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt, tolerance );
6703     }
6704     TIDSortedElemSet suspectElems;
6705     _ebbTree->getElementsNearPoint( point, suspectElems );
6706     TIDSortedElemSet::iterator elem = suspectElems.begin();
6707     for ( ; elem != suspectElems.end(); ++elem )
6708       if ( !SMESH_MeshEditor::IsOut( *elem, point, tolerance ))
6709         foundElements.push_back( *elem );
6710   }
6711   return foundElements.size();
6712 }
6713
6714 //=======================================================================
6715 /*!
6716  * \brief Find an element of given type most close to the given point
6717  *
6718  * WARNING: Only face search is implemeneted so far
6719  */
6720 //=======================================================================
6721
6722 const SMDS_MeshElement*
6723 SMESH_ElementSearcherImpl::FindClosestTo( const gp_Pnt&       point,
6724                                           SMDSAbs_ElementType type )
6725 {
6726   const SMDS_MeshElement* closestElem = 0;
6727
6728   if ( type == SMDSAbs_Face )
6729   {
6730     if ( !_ebbTree || _elementType != type )
6731     {
6732       if ( _ebbTree ) delete _ebbTree;
6733       _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt );
6734     }
6735     TIDSortedElemSet suspectElems;
6736     _ebbTree->getElementsNearPoint( point, suspectElems );
6737     
6738     if ( suspectElems.empty() && _ebbTree->maxSize() > 0 )
6739     {
6740       gp_Pnt boxCenter = 0.5 * ( _ebbTree->getBox().CornerMin() +
6741                                  _ebbTree->getBox().CornerMax() );
6742       double radius;
6743       if ( _ebbTree->getBox().IsOut( point.XYZ() ))
6744         radius = point.Distance( boxCenter ) - 0.5 * _ebbTree->maxSize();
6745       else
6746         radius = _ebbTree->maxSize() / pow( 2., _ebbTree->getHeight()) / 2;
6747       while ( suspectElems.empty() )
6748       {
6749         _ebbTree->getElementsInSphere( point.XYZ(), radius, suspectElems );
6750         radius *= 1.1;
6751       }
6752     }
6753     double minDist = std::numeric_limits<double>::max();
6754     multimap< double, const SMDS_MeshElement* > dist2face;
6755     TIDSortedElemSet::iterator elem = suspectElems.begin();
6756     for ( ; elem != suspectElems.end(); ++elem )
6757     {
6758       double dist = SMESH_MeshEditor::GetDistance( dynamic_cast<const SMDS_MeshFace*>(*elem),
6759                                                    point );
6760       if ( dist < minDist + 1e-10)
6761       {
6762         minDist = dist;
6763         dist2face.insert( dist2face.begin(), make_pair( dist, *elem ));
6764       }
6765     }
6766     if ( !dist2face.empty() )
6767     {
6768       multimap< double, const SMDS_MeshElement* >::iterator d2f = dist2face.begin();
6769       closestElem = d2f->second;
6770       // if there are several elements at the same distance, select one
6771       // with GC closest to the point
6772       typedef SMDS_StdIterator< SMESH_TNodeXYZ, SMDS_ElemIteratorPtr > TXyzIterator;
6773       double minDistToGC = 0;
6774       for ( ++d2f; d2f != dist2face.end() && fabs( d2f->first - minDist ) < 1e-10; ++d2f )
6775       {
6776         if ( minDistToGC == 0 )
6777         {
6778           gp_XYZ gc(0,0,0);
6779           gc = accumulate( TXyzIterator(closestElem->nodesIterator()),
6780                            TXyzIterator(), gc ) / closestElem->NbNodes();
6781           minDistToGC = point.SquareDistance( gc );
6782         }
6783         gp_XYZ gc(0,0,0);
6784         gc = accumulate( TXyzIterator( d2f->second->nodesIterator()),
6785                          TXyzIterator(), gc ) / d2f->second->NbNodes();
6786         double d = point.SquareDistance( gc );
6787         if ( d < minDistToGC )
6788         {
6789           minDistToGC = d;
6790           closestElem = d2f->second;
6791         }
6792       }
6793       // cout << "FindClosestTo( " <<point.X()<<", "<<point.Y()<<", "<<point.Z()<<" ) FACE "
6794       //      <<closestElem->GetID() << " DIST " << minDist << endl;
6795     }
6796   }
6797   else
6798   {
6799     // NOT IMPLEMENTED SO FAR
6800   }
6801   return closestElem;
6802 }
6803
6804
6805 //================================================================================
6806 /*!
6807  * \brief Classify the given point in the closed 2D mesh
6808  */
6809 //================================================================================
6810
6811 TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
6812 {
6813   double tolerance = getTolerance();
6814   if ( !_ebbTree || _elementType != SMDSAbs_Face )
6815   {
6816     if ( _ebbTree ) delete _ebbTree;
6817     _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = SMDSAbs_Face, _meshPartIt );
6818   }
6819   // Algo: analyse transition of a line starting at the point through mesh boundary;
6820   // try three lines parallel to axis of the coordinate system and perform rough
6821   // analysis. If solution is not clear perform thorough analysis.
6822
6823   const int nbAxes = 3;
6824   gp_Dir axisDir[ nbAxes ] = { gp::DX(), gp::DY(), gp::DZ() };
6825   map< double, TInters >   paramOnLine2TInters[ nbAxes ];
6826   list< TInters > tangentInters[ nbAxes ]; // of faces whose plane includes the line
6827   multimap< int, int > nbInt2Axis; // to find the simplest case
6828   for ( int axis = 0; axis < nbAxes; ++axis )
6829   {
6830     gp_Ax1 lineAxis( point, axisDir[axis]);
6831     gp_Lin line    ( lineAxis );
6832
6833     TIDSortedElemSet suspectFaces; // faces possibly intersecting the line
6834     _ebbTree->getElementsNearLine( lineAxis, suspectFaces );
6835
6836     // Intersect faces with the line
6837
6838     map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6839     TIDSortedElemSet::iterator face = suspectFaces.begin();
6840     for ( ; face != suspectFaces.end(); ++face )
6841     {
6842       // get face plane
6843       gp_XYZ fNorm;
6844       if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false)) continue;
6845       gp_Pln facePlane( SMESH_TNodeXYZ( (*face)->GetNode(0)), fNorm );
6846
6847       // perform intersection
6848       IntAna_IntConicQuad intersection( line, IntAna_Quadric( facePlane ));
6849       if ( !intersection.IsDone() )
6850         continue;
6851       if ( intersection.IsInQuadric() )
6852       {
6853         tangentInters[ axis ].push_back( TInters( *face, fNorm, true ));
6854       }
6855       else if ( ! intersection.IsParallel() && intersection.NbPoints() > 0 )
6856       {
6857         gp_Pnt intersectionPoint = intersection.Point(1);
6858         if ( !SMESH_MeshEditor::IsOut( *face, intersectionPoint, tolerance ))
6859           u2inters.insert(make_pair( intersection.ParamOnConic(1), TInters( *face, fNorm )));
6860       }
6861     }
6862     // Analyse intersections roughly
6863
6864     int nbInter = u2inters.size();
6865     if ( nbInter == 0 )
6866       return TopAbs_OUT;
6867
6868     double f = u2inters.begin()->first, l = u2inters.rbegin()->first;
6869     if ( nbInter == 1 ) // not closed mesh
6870       return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6871
6872     if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6873       return TopAbs_ON;
6874
6875     if ( (f<0) == (l<0) )
6876       return TopAbs_OUT;
6877
6878     int nbIntBeforePoint = std::distance( u2inters.begin(), u2inters.lower_bound(0));
6879     int nbIntAfterPoint  = nbInter - nbIntBeforePoint;
6880     if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6881       return TopAbs_IN;
6882
6883     nbInt2Axis.insert( make_pair( min( nbIntBeforePoint, nbIntAfterPoint ), axis ));
6884
6885     if ( _outerFacesFound ) break; // pass to thorough analysis
6886
6887   } // three attempts - loop on CS axes
6888
6889   // Analyse intersections thoroughly.
6890   // We make two loops maximum, on the first one we only exclude touching intersections,
6891   // on the second, if situation is still unclear, we gather and use information on
6892   // position of faces (internal or outer). If faces position is already gathered,
6893   // we make the second loop right away.
6894
6895   for ( int hasPositionInfo = _outerFacesFound; hasPositionInfo < 2; ++hasPositionInfo )
6896   {
6897     multimap< int, int >::const_iterator nb_axis = nbInt2Axis.begin();
6898     for ( ; nb_axis != nbInt2Axis.end(); ++nb_axis )
6899     {
6900       int axis = nb_axis->second;
6901       map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6902
6903       gp_Ax1 lineAxis( point, axisDir[axis]);
6904       gp_Lin line    ( lineAxis );
6905
6906       // add tangent intersections to u2inters
6907       double param;
6908       list< TInters >::const_iterator tgtInt = tangentInters[ axis ].begin();
6909       for ( ; tgtInt != tangentInters[ axis ].end(); ++tgtInt )
6910         if ( getIntersParamOnLine( line, tgtInt->_face, tolerance, param ))
6911           u2inters.insert(make_pair( param, *tgtInt ));
6912       tangentInters[ axis ].clear();
6913
6914       // Count intersections before and after the point excluding touching ones.
6915       // If hasPositionInfo we count intersections of outer boundary only
6916
6917       int nbIntBeforePoint = 0, nbIntAfterPoint = 0;
6918       double f = numeric_limits<double>::max(), l = -numeric_limits<double>::max();
6919       map< double, TInters >::iterator u_int1 = u2inters.begin(), u_int2 = u_int1;
6920       bool ok = ! u_int1->second._coincides;
6921       while ( ok && u_int1 != u2inters.end() )
6922       {
6923         double u = u_int1->first;
6924         bool touchingInt = false;
6925         if ( ++u_int2 != u2inters.end() )
6926         {
6927           // skip intersections at the same point (if the line passes through edge or node)
6928           int nbSamePnt = 0;
6929           while ( u_int2 != u2inters.end() && fabs( u_int2->first - u ) < tolerance )
6930           {
6931             ++nbSamePnt;
6932             ++u_int2;
6933           }
6934
6935           // skip tangent intersections
6936           int nbTgt = 0;
6937           const SMDS_MeshElement* prevFace = u_int1->second._face;
6938           while ( ok && u_int2->second._coincides )
6939           {
6940             if ( SMESH_Algo::GetCommonNodes(prevFace , u_int2->second._face).empty() )
6941               ok = false;
6942             else
6943             {
6944               nbTgt++;
6945               u_int2++;
6946               ok = ( u_int2 != u2inters.end() );
6947             }
6948           }
6949           if ( !ok ) break;
6950
6951           // skip intersections at the same point after tangent intersections
6952           if ( nbTgt > 0 )
6953           {
6954             double u2 = u_int2->first;
6955             ++u_int2;
6956             while ( u_int2 != u2inters.end() && fabs( u_int2->first - u2 ) < tolerance )
6957             {
6958               ++nbSamePnt;
6959               ++u_int2;
6960             }
6961           }
6962           // decide if we skipped a touching intersection
6963           if ( nbSamePnt + nbTgt > 0 )
6964           {
6965             double minDot = numeric_limits<double>::max(), maxDot = -numeric_limits<double>::max();
6966             map< double, TInters >::iterator u_int = u_int1;
6967             for ( ; u_int != u_int2; ++u_int )
6968             {
6969               if ( u_int->second._coincides ) continue;
6970               double dot = u_int->second._faceNorm * line.Direction();
6971               if ( dot > maxDot ) maxDot = dot;
6972               if ( dot < minDot ) minDot = dot;
6973             }
6974             touchingInt = ( minDot*maxDot < 0 );
6975           }
6976         }
6977         if ( !touchingInt )
6978         {
6979           if ( !hasPositionInfo || isOuterBoundary( u_int1->second._face ))
6980           {
6981             if ( u < 0 )
6982               ++nbIntBeforePoint;
6983             else
6984               ++nbIntAfterPoint;
6985           }
6986           if ( u < f ) f = u;
6987           if ( u > l ) l = u;
6988         }
6989
6990         u_int1 = u_int2; // to next intersection
6991
6992       } // loop on intersections with one line
6993
6994       if ( ok )
6995       {
6996         if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6997           return TopAbs_ON;
6998
6999         if ( nbIntBeforePoint == 0  || nbIntAfterPoint == 0)
7000           return TopAbs_OUT;
7001
7002         if ( nbIntBeforePoint + nbIntAfterPoint == 1 ) // not closed mesh
7003           return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
7004
7005         if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
7006           return TopAbs_IN;
7007
7008         if ( (f<0) == (l<0) )
7009           return TopAbs_OUT;
7010
7011         if ( hasPositionInfo )
7012           return nbIntBeforePoint % 2 ? TopAbs_IN : TopAbs_OUT;
7013       }
7014     } // loop on intersections of the tree lines - thorough analysis
7015
7016     if ( !hasPositionInfo )
7017     {
7018       // gather info on faces position - is face in the outer boundary or not
7019       map< double, TInters > & u2inters = paramOnLine2TInters[ 0 ];
7020       findOuterBoundary( u2inters.begin()->second._face );
7021     }
7022
7023   } // two attempts - with and w/o faces position info in the mesh
7024
7025   return TopAbs_UNKNOWN;
7026 }
7027
7028 //=======================================================================
7029 /*!
7030  * \brief Return elements possibly intersecting the line
7031  */
7032 //=======================================================================
7033
7034 void SMESH_ElementSearcherImpl::GetElementsNearLine( const gp_Ax1&                      line,
7035                                                      SMDSAbs_ElementType                type,
7036                                                      vector< const SMDS_MeshElement* >& foundElems)
7037 {
7038   if ( !_ebbTree || _elementType != type )
7039   {
7040     if ( _ebbTree ) delete _ebbTree;
7041     _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt );
7042   }
7043   TIDSortedElemSet suspectFaces; // elements possibly intersecting the line
7044   _ebbTree->getElementsNearLine( line, suspectFaces );
7045   foundElems.assign( suspectFaces.begin(), suspectFaces.end());
7046 }
7047
7048 //=======================================================================
7049 /*!
7050  * \brief Return SMESH_ElementSearcher
7051  */
7052 //=======================================================================
7053
7054 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher()
7055 {
7056   return new SMESH_ElementSearcherImpl( *GetMeshDS() );
7057 }
7058
7059 //=======================================================================
7060 /*!
7061  * \brief Return SMESH_ElementSearcher acting on a sub-set of elements
7062  */
7063 //=======================================================================
7064
7065 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher(SMDS_ElemIteratorPtr elemIt)
7066 {
7067   return new SMESH_ElementSearcherImpl( *GetMeshDS(), elemIt );
7068 }
7069
7070 //=======================================================================
7071 /*!
7072  * \brief Return true if the point is IN or ON of the element
7073  */
7074 //=======================================================================
7075
7076 bool SMESH_MeshEditor::IsOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol )
7077 {
7078   if ( element->GetType() == SMDSAbs_Volume)
7079   {
7080     return SMDS_VolumeTool( element ).IsOut( point.X(), point.Y(), point.Z(), tol );
7081   }
7082
7083   // get ordered nodes
7084
7085   vector< gp_XYZ > xyz;
7086   vector<const SMDS_MeshNode*> nodeList;
7087
7088   SMDS_ElemIteratorPtr nodeIt = element->nodesIterator();
7089   if ( element->IsQuadratic() ) {
7090     if (const SMDS_VtkFace* f=dynamic_cast<const SMDS_VtkFace*>(element))
7091       nodeIt = f->interlacedNodesElemIterator();
7092     else if (const SMDS_VtkEdge*  e =dynamic_cast<const SMDS_VtkEdge*>(element))
7093       nodeIt = e->interlacedNodesElemIterator();
7094   }
7095   while ( nodeIt->more() )
7096     {
7097       const SMDS_MeshNode* node = cast2Node( nodeIt->next() );
7098       xyz.push_back( SMESH_TNodeXYZ(node) );
7099       nodeList.push_back(node);
7100     }
7101
7102   int i, nbNodes = element->NbNodes();
7103
7104   if ( element->GetType() == SMDSAbs_Face ) // --------------------------------------------------
7105   {
7106     // compute face normal
7107     gp_Vec faceNorm(0,0,0);
7108     xyz.push_back( xyz.front() );
7109     nodeList.push_back( nodeList.front() );
7110     for ( i = 0; i < nbNodes; ++i )
7111     {
7112       gp_Vec edge1( xyz[i+1], xyz[i]);
7113       gp_Vec edge2( xyz[i+1], xyz[(i+2)%nbNodes] );
7114       faceNorm += edge1 ^ edge2;
7115     }
7116     double normSize = faceNorm.Magnitude();
7117     if ( normSize <= tol )
7118     {
7119       // degenerated face: point is out if it is out of all face edges
7120       for ( i = 0; i < nbNodes; ++i )
7121       {
7122         SMDS_LinearEdge edge( nodeList[i], nodeList[i+1] );
7123         if ( !IsOut( &edge, point, tol ))
7124           return false;
7125       }
7126       return true;
7127     }
7128     faceNorm /= normSize;
7129
7130     // check if the point lays on face plane
7131     gp_Vec n2p( xyz[0], point );
7132     if ( fabs( n2p * faceNorm ) > tol )
7133       return true; // not on face plane
7134
7135     // check if point is out of face boundary:
7136     // define it by closest transition of a ray point->infinity through face boundary
7137     // on the face plane.
7138     // First, find normal of a plane perpendicular to face plane, to be used as a cutting tool
7139     // to find intersections of the ray with the boundary.
7140     gp_Vec ray = n2p;
7141     gp_Vec plnNorm = ray ^ faceNorm;
7142     normSize = plnNorm.Magnitude();
7143     if ( normSize <= tol ) return false; // point coincides with the first node
7144     plnNorm /= normSize;
7145     // for each node of the face, compute its signed distance to the plane
7146     vector<double> dist( nbNodes + 1);
7147     for ( i = 0; i < nbNodes; ++i )
7148     {
7149       gp_Vec n2p( xyz[i], point );
7150       dist[i] = n2p * plnNorm;
7151     }
7152     dist.back() = dist.front();
7153     // find the closest intersection
7154     int    iClosest = -1;
7155     double rClosest, distClosest = 1e100;;
7156     gp_Pnt pClosest;
7157     for ( i = 0; i < nbNodes; ++i )
7158     {
7159       double r;
7160       if ( fabs( dist[i]) < tol )
7161         r = 0.;
7162       else if ( fabs( dist[i+1]) < tol )
7163         r = 1.;
7164       else if ( dist[i] * dist[i+1] < 0 )
7165         r = dist[i] / ( dist[i] - dist[i+1] );
7166       else
7167         continue; // no intersection
7168       gp_Pnt pInt = xyz[i] * (1.-r) + xyz[i+1] * r;
7169       gp_Vec p2int ( point, pInt);
7170       if ( p2int * ray > -tol ) // right half-space
7171       {
7172         double intDist = p2int.SquareMagnitude();
7173         if ( intDist < distClosest )
7174         {
7175           iClosest = i;
7176           rClosest = r;
7177           pClosest = pInt;
7178           distClosest = intDist;
7179         }
7180       }
7181     }
7182     if ( iClosest < 0 )
7183       return true; // no intesections - out
7184
7185     // analyse transition
7186     gp_Vec edge( xyz[iClosest], xyz[iClosest+1] );
7187     gp_Vec edgeNorm = -( edge ^ faceNorm ); // normal to intersected edge pointing out of face
7188     gp_Vec p2int ( point, pClosest );
7189     bool out = (edgeNorm * p2int) < -tol;
7190     if ( rClosest > 0. && rClosest < 1. ) // not node intersection
7191       return out;
7192
7193     // ray pass through a face node; analyze transition through an adjacent edge
7194     gp_Pnt p1 = xyz[ (rClosest == 0.) ? ((iClosest+nbNodes-1) % nbNodes) : (iClosest+1) ];
7195     gp_Pnt p2 = xyz[ (rClosest == 0.) ? iClosest : ((iClosest+2) % nbNodes) ];
7196     gp_Vec edgeAdjacent( p1, p2 );
7197     gp_Vec edgeNorm2 = -( edgeAdjacent ^ faceNorm );
7198     bool out2 = (edgeNorm2 * p2int) < -tol;
7199
7200     bool covexCorner = ( edgeNorm * edgeAdjacent * (rClosest==1. ? 1. : -1.)) < 0;
7201     return covexCorner ? (out || out2) : (out && out2);
7202   }
7203   if ( element->GetType() == SMDSAbs_Edge ) // --------------------------------------------------
7204   {
7205     // point is out of edge if it is NOT ON any straight part of edge
7206     // (we consider quadratic edge as being composed of two straight parts)
7207     for ( i = 1; i < nbNodes; ++i )
7208     {
7209       gp_Vec edge( xyz[i-1], xyz[i]);
7210       gp_Vec n1p ( xyz[i-1], point);
7211       double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude();
7212       if ( dist > tol )
7213         continue;
7214       gp_Vec n2p( xyz[i], point );
7215       if ( fabs( edge.Magnitude() - n1p.Magnitude() - n2p.Magnitude()) > tol )
7216         continue;
7217       return false; // point is ON this part
7218     }
7219     return true;
7220   }
7221   // Node or 0D element -------------------------------------------------------------------------
7222   {
7223     gp_Vec n2p ( xyz[0], point );
7224     return n2p.Magnitude() <= tol;
7225   }
7226   return true;
7227 }
7228
7229 //=======================================================================
7230
7231 namespace
7232 {
7233   // Position of a point relative to a segment
7234   //            .           .
7235   //            .  LEFT     .
7236   //            .           .
7237   //  VERTEX 1  o----ON----->  VERTEX 2
7238   //            .           .
7239   //            .  RIGHT    .
7240   //            .           .
7241   enum PositionName { POS_LEFT = 1, POS_VERTEX = 2, POS_RIGHT = 4, //POS_ON = 8,
7242                       POS_ALL = POS_LEFT | POS_RIGHT | POS_VERTEX };
7243   struct PointPos
7244   {
7245     PositionName _name; 
7246     int          _index; // index of vertex or segment
7247
7248     PointPos( PositionName n, int i=-1 ): _name(n), _index(i) {}
7249     bool operator < (const PointPos& other ) const
7250     {
7251       if ( _name == other._name )
7252         return  ( _index < 0 || other._index < 0 ) ? false : _index < other._index;
7253       return _name < other._name;
7254     }
7255   };
7256
7257   //================================================================================
7258   /*!
7259    * \brief Return of a point relative to a segment
7260    *  \param point2D      - the point to analyze position of
7261    *  \param xyVec        - end points of segments
7262    *  \param index0       - 0-based index of the first point of segment
7263    *  \param posToFindOut - flags of positions to detect
7264    *  \retval PointPos - point position
7265    */
7266   //================================================================================
7267
7268   PointPos getPointPosition( const gp_XY& point2D,
7269                              const gp_XY* segEnds,
7270                              const int    index0 = 0,
7271                              const int    posToFindOut = POS_ALL)
7272   {
7273     const gp_XY& p1 = segEnds[ index0   ];
7274     const gp_XY& p2 = segEnds[ index0+1 ];
7275     const gp_XY grad = p2 - p1;
7276
7277     if ( posToFindOut & POS_VERTEX )
7278     {
7279       // check if the point2D is at "vertex 1" zone
7280       gp_XY pp1[2] = { p1, gp_XY( p1.X() - grad.Y(),
7281                                   p1.Y() + grad.X() ) };
7282       if ( getPointPosition( point2D, pp1, 0, POS_LEFT|POS_RIGHT )._name == POS_LEFT )
7283         return PointPos( POS_VERTEX, index0 );
7284
7285       // check if the point2D is at "vertex 2" zone
7286       gp_XY pp2[2] = { p2, gp_XY( p2.X() - grad.Y(),
7287                                   p2.Y() + grad.X() ) };
7288       if ( getPointPosition( point2D, pp2, 0, POS_LEFT|POS_RIGHT )._name == POS_RIGHT )
7289         return PointPos( POS_VERTEX, index0 + 1);
7290     }
7291     double edgeEquation =
7292       ( point2D.X() - p1.X() ) * grad.Y() - ( point2D.Y() - p1.Y() ) * grad.X();
7293     return PointPos( edgeEquation < 0 ? POS_LEFT : POS_RIGHT, index0 );
7294   }
7295 }
7296
7297 //=======================================================================
7298 /*!
7299  * \brief Return minimal distance from a point to a face
7300  *
7301  * Currently we ignore non-planarity and 2nd order of face
7302  */
7303 //=======================================================================
7304
7305 double SMESH_MeshEditor::GetDistance( const SMDS_MeshFace* face,
7306                                       const gp_Pnt&        point )
7307 {
7308   double badDistance = -1;
7309   if ( !face ) return badDistance;
7310
7311   // coordinates of nodes (medium nodes, if any, ignored)
7312   typedef SMDS_StdIterator< SMESH_TNodeXYZ, SMDS_ElemIteratorPtr > TXyzIterator;
7313   vector<gp_XYZ> xyz( TXyzIterator( face->nodesIterator()), TXyzIterator() );
7314   xyz.resize( face->NbCornerNodes()+1 );
7315
7316   // transformation to get xyz[0] lies on the origin, xyz[1] lies on the Z axis,
7317   // and xyz[2] lies in the XZ plane. This is to pass to 2D space on XZ plane.
7318   gp_Trsf trsf;
7319   gp_Vec OZ ( xyz[0], xyz[1] );
7320   gp_Vec OX ( xyz[0], xyz[2] );
7321   if ( OZ.Magnitude() < std::numeric_limits<double>::min() )
7322   {
7323     if ( xyz.size() < 4 ) return badDistance;
7324     OZ = gp_Vec ( xyz[0], xyz[2] );
7325     OX = gp_Vec ( xyz[0], xyz[3] );
7326   }
7327   gp_Ax3 tgtCS;
7328   try {
7329     tgtCS = gp_Ax3( xyz[0], OZ, OX );
7330   }
7331   catch ( Standard_Failure ) {
7332     return badDistance;
7333   }
7334   trsf.SetTransformation( tgtCS );
7335
7336   // move all the nodes to 2D
7337   vector<gp_XY> xy( xyz.size() );
7338   for ( size_t i = 0;i < xyz.size()-1; ++i )
7339   {
7340     gp_XYZ p3d = xyz[i];
7341     trsf.Transforms( p3d );
7342     xy[i].SetCoord( p3d.X(), p3d.Z() );
7343   }
7344   xyz.back() = xyz.front();
7345   xy.back() = xy.front();
7346
7347   // // move the point in 2D
7348   gp_XYZ tmpPnt = point.XYZ();
7349   trsf.Transforms( tmpPnt );
7350   gp_XY point2D( tmpPnt.X(), tmpPnt.Z() );
7351
7352   // loop on segments of the face to analyze point position ralative to the face
7353   set< PointPos > pntPosSet;
7354   for ( size_t i = 1; i < xy.size(); ++i )
7355   {
7356     PointPos pos = getPointPosition( point2D, &xy[0], i-1 );
7357     pntPosSet.insert( pos );
7358   }
7359
7360   // compute distance
7361   PointPos pos = *pntPosSet.begin();
7362   // cout << "Face " << face->GetID() << " DIST: ";
7363   switch ( pos._name )
7364   {
7365   case POS_LEFT: {
7366     // point is most close to a segment
7367     gp_Vec p0p1( point, xyz[ pos._index ] );
7368     gp_Vec p1p2( xyz[ pos._index ], xyz[ pos._index+1 ]); // segment vector
7369     p1p2.Normalize();
7370     double projDist = p0p1 * p1p2; // distance projected to the segment
7371     gp_Vec projVec = p1p2 * projDist;
7372     gp_Vec distVec = p0p1 - projVec;
7373     // cout << distVec.Magnitude()  << ", SEG " << face->GetNode(pos._index)->GetID()
7374     //      << " - " << face->GetNodeWrap(pos._index+1)->GetID() << endl;
7375     return distVec.Magnitude();
7376   }
7377   case POS_RIGHT: {
7378     // point is inside the face
7379     double distToFacePlane = tmpPnt.Y();
7380     // cout << distToFacePlane << ", INSIDE " << endl;
7381     return Abs( distToFacePlane );
7382   }
7383   case POS_VERTEX: {
7384     // point is most close to a node
7385     gp_Vec distVec( point, xyz[ pos._index ]);
7386     // cout << distVec.Magnitude()  << " VERTEX " << face->GetNode(pos._index)->GetID() << endl;
7387     return distVec.Magnitude();
7388   }
7389   }
7390   return badDistance;
7391 }
7392
7393 //=======================================================================
7394 //function : SimplifyFace
7395 //purpose  :
7396 //=======================================================================
7397 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *> faceNodes,
7398                                     vector<const SMDS_MeshNode *>&      poly_nodes,
7399                                     vector<int>&                        quantities) const
7400 {
7401   int nbNodes = faceNodes.size();
7402
7403   if (nbNodes < 3)
7404     return 0;
7405
7406   set<const SMDS_MeshNode*> nodeSet;
7407
7408   // get simple seq of nodes
7409   //const SMDS_MeshNode* simpleNodes[ nbNodes ];
7410   vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
7411   int iSimple = 0, nbUnique = 0;
7412
7413   simpleNodes[iSimple++] = faceNodes[0];
7414   nbUnique++;
7415   for (int iCur = 1; iCur < nbNodes; iCur++) {
7416     if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
7417       simpleNodes[iSimple++] = faceNodes[iCur];
7418       if (nodeSet.insert( faceNodes[iCur] ).second)
7419         nbUnique++;
7420     }
7421   }
7422   int nbSimple = iSimple;
7423   if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
7424     nbSimple--;
7425     iSimple--;
7426   }
7427
7428   if (nbUnique < 3)
7429     return 0;
7430
7431   // separate loops
7432   int nbNew = 0;
7433   bool foundLoop = (nbSimple > nbUnique);
7434   while (foundLoop) {
7435     foundLoop = false;
7436     set<const SMDS_MeshNode*> loopSet;
7437     for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
7438       const SMDS_MeshNode* n = simpleNodes[iSimple];
7439       if (!loopSet.insert( n ).second) {
7440         foundLoop = true;
7441
7442         // separate loop
7443         int iC = 0, curLast = iSimple;
7444         for (; iC < curLast; iC++) {
7445           if (simpleNodes[iC] == n) break;
7446         }
7447         int loopLen = curLast - iC;
7448         if (loopLen > 2) {
7449           // create sub-element
7450           nbNew++;
7451           quantities.push_back(loopLen);
7452           for (; iC < curLast; iC++) {
7453             poly_nodes.push_back(simpleNodes[iC]);
7454           }
7455         }
7456         // shift the rest nodes (place from the first loop position)
7457         for (iC = curLast + 1; iC < nbSimple; iC++) {
7458           simpleNodes[iC - loopLen] = simpleNodes[iC];
7459         }
7460         nbSimple -= loopLen;
7461         iSimple -= loopLen;
7462       }
7463     } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
7464   } // while (foundLoop)
7465
7466   if (iSimple > 2) {
7467     nbNew++;
7468     quantities.push_back(iSimple);
7469     for (int i = 0; i < iSimple; i++)
7470       poly_nodes.push_back(simpleNodes[i]);
7471   }
7472
7473   return nbNew;
7474 }
7475
7476 //=======================================================================
7477 //function : MergeNodes
7478 //purpose  : In each group, the cdr of nodes are substituted by the first one
7479 //           in all elements.
7480 //=======================================================================
7481
7482 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
7483 {
7484   MESSAGE("MergeNodes");
7485   myLastCreatedElems.Clear();
7486   myLastCreatedNodes.Clear();
7487
7488   SMESHDS_Mesh* aMesh = GetMeshDS();
7489
7490   TNodeNodeMap nodeNodeMap; // node to replace - new node
7491   set<const SMDS_MeshElement*> elems; // all elements with changed nodes
7492   list< int > rmElemIds, rmNodeIds;
7493
7494   // Fill nodeNodeMap and elems
7495
7496   TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
7497   for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
7498     list<const SMDS_MeshNode*>& nodes = *grIt;
7499     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
7500     const SMDS_MeshNode* nToKeep = *nIt;
7501     //MESSAGE("node to keep " << nToKeep->GetID());
7502     for ( ++nIt; nIt != nodes.end(); nIt++ ) {
7503       const SMDS_MeshNode* nToRemove = *nIt;
7504       nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
7505       if ( nToRemove != nToKeep ) {
7506         //MESSAGE("  node to remove " << nToRemove->GetID());
7507         rmNodeIds.push_back( nToRemove->GetID() );
7508         AddToSameGroups( nToKeep, nToRemove, aMesh );
7509       }
7510
7511       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
7512       while ( invElemIt->more() ) {
7513         const SMDS_MeshElement* elem = invElemIt->next();
7514         elems.insert(elem);
7515       }
7516     }
7517   }
7518   // Change element nodes or remove an element
7519
7520   set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
7521   for ( ; eIt != elems.end(); eIt++ ) {
7522     const SMDS_MeshElement* elem = *eIt;
7523     //MESSAGE(" ---- inverse elem on node to remove " << elem->GetID());
7524     int nbNodes = elem->NbNodes();
7525     int aShapeId = FindShape( elem );
7526
7527     set<const SMDS_MeshNode*> nodeSet;
7528     vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
7529     int iUnique = 0, iCur = 0, nbRepl = 0;
7530     vector<int> iRepl( nbNodes );
7531
7532     // get new seq of nodes
7533     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
7534     while ( itN->more() ) {
7535       const SMDS_MeshNode* n =
7536         static_cast<const SMDS_MeshNode*>( itN->next() );
7537
7538       TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
7539       if ( nnIt != nodeNodeMap.end() ) { // n sticks
7540         n = (*nnIt).second;
7541         // BUG 0020185: begin
7542         {
7543           bool stopRecur = false;
7544           set<const SMDS_MeshNode*> nodesRecur;
7545           nodesRecur.insert(n);
7546           while (!stopRecur) {
7547             TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
7548             if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
7549               n = (*nnIt_i).second;
7550               if (!nodesRecur.insert(n).second) {
7551                 // error: recursive dependancy
7552                 stopRecur = true;
7553               }
7554             }
7555             else
7556               stopRecur = true;
7557           }
7558         }
7559         // BUG 0020185: end
7560       }
7561       curNodes[ iCur ] = n;
7562       bool isUnique = nodeSet.insert( n ).second;
7563       if ( isUnique )
7564         uniqueNodes[ iUnique++ ] = n;
7565       else
7566         iRepl[ nbRepl++ ] = iCur;
7567       iCur++;
7568     }
7569
7570     // Analyse element topology after replacement
7571
7572     bool isOk = true;
7573     int nbUniqueNodes = nodeSet.size();
7574     //MESSAGE("nbNodes nbUniqueNodes " << nbNodes << " " << nbUniqueNodes);
7575     if ( nbNodes != nbUniqueNodes ) { // some nodes stick
7576       // Polygons and Polyhedral volumes
7577       if (elem->IsPoly()) {
7578
7579         if (elem->GetType() == SMDSAbs_Face) {
7580           // Polygon
7581           vector<const SMDS_MeshNode *> face_nodes (nbNodes);
7582           int inode = 0;
7583           for (; inode < nbNodes; inode++) {
7584             face_nodes[inode] = curNodes[inode];
7585           }
7586
7587           vector<const SMDS_MeshNode *> polygons_nodes;
7588           vector<int> quantities;
7589           int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
7590           if (nbNew > 0) {
7591             inode = 0;
7592             for (int iface = 0; iface < nbNew; iface++) {
7593               int nbNodes = quantities[iface];
7594               vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
7595               for (int ii = 0; ii < nbNodes; ii++, inode++) {
7596                 poly_nodes[ii] = polygons_nodes[inode];
7597               }
7598               SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
7599               myLastCreatedElems.Append(newElem);
7600               if (aShapeId)
7601                 aMesh->SetMeshElementOnShape(newElem, aShapeId);
7602             }
7603
7604             MESSAGE("ChangeElementNodes MergeNodes Polygon");
7605             //aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
7606             vector<const SMDS_MeshNode *> polynodes(polygons_nodes.begin()+inode,polygons_nodes.end());
7607             int quid =0;
7608             if (nbNew > 0) quid = nbNew - 1;
7609             vector<int> newquant(quantities.begin()+quid, quantities.end());
7610             const SMDS_MeshElement* newElem = 0;
7611             newElem = aMesh->AddPolyhedralVolume(polynodes, newquant);
7612             myLastCreatedElems.Append(newElem);
7613             if ( aShapeId && newElem )
7614               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7615             rmElemIds.push_back(elem->GetID());
7616           }
7617           else {
7618             rmElemIds.push_back(elem->GetID());
7619           }
7620
7621         }
7622         else if (elem->GetType() == SMDSAbs_Volume) {
7623           // Polyhedral volume
7624           if (nbUniqueNodes < 4) {
7625             rmElemIds.push_back(elem->GetID());
7626           }
7627           else {
7628             // each face has to be analyzed in order to check volume validity
7629             const SMDS_VtkVolume* aPolyedre =
7630               dynamic_cast<const SMDS_VtkVolume*>( elem );
7631             if (aPolyedre) {
7632               int nbFaces = aPolyedre->NbFaces();
7633
7634               vector<const SMDS_MeshNode *> poly_nodes;
7635               vector<int> quantities;
7636
7637               for (int iface = 1; iface <= nbFaces; iface++) {
7638                 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7639                 vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
7640
7641                 for (int inode = 1; inode <= nbFaceNodes; inode++) {
7642                   const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
7643                   TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
7644                   if (nnIt != nodeNodeMap.end()) { // faceNode sticks
7645                     faceNode = (*nnIt).second;
7646                   }
7647                   faceNodes[inode - 1] = faceNode;
7648                 }
7649
7650                 SimplifyFace(faceNodes, poly_nodes, quantities);
7651               }
7652
7653               if (quantities.size() > 3) {
7654                 // to be done: remove coincident faces
7655               }
7656
7657               if (quantities.size() > 3)
7658                 {
7659                   MESSAGE("ChangeElementNodes MergeNodes Polyhedron");
7660                   //aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
7661                   const SMDS_MeshElement* newElem = 0;
7662                   newElem = aMesh->AddPolyhedralVolume(poly_nodes, quantities);
7663                   myLastCreatedElems.Append(newElem);
7664                   if ( aShapeId && newElem )
7665                     aMesh->SetMeshElementOnShape( newElem, aShapeId );
7666                   rmElemIds.push_back(elem->GetID());
7667                 }
7668             }
7669             else {
7670               rmElemIds.push_back(elem->GetID());
7671             }
7672           }
7673         }
7674         else {
7675         }
7676
7677         continue;
7678       } // poly element
7679
7680       // Regular elements
7681       // TODO not all the possible cases are solved. Find something more generic?
7682       switch ( nbNodes ) {
7683       case 2: ///////////////////////////////////// EDGE
7684         isOk = false; break;
7685       case 3: ///////////////////////////////////// TRIANGLE
7686         isOk = false; break;
7687       case 4:
7688         if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
7689           isOk = false;
7690         else { //////////////////////////////////// QUADRANGLE
7691           if ( nbUniqueNodes < 3 )
7692             isOk = false;
7693           else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
7694             isOk = false; // opposite nodes stick
7695           //MESSAGE("isOk " << isOk);
7696         }
7697         break;
7698       case 6: ///////////////////////////////////// PENTAHEDRON
7699         if ( nbUniqueNodes == 4 ) {
7700           // ---------------------------------> tetrahedron
7701           if (nbRepl == 3 &&
7702               iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
7703             // all top nodes stick: reverse a bottom
7704             uniqueNodes[ 0 ] = curNodes [ 1 ];
7705             uniqueNodes[ 1 ] = curNodes [ 0 ];
7706           }
7707           else if (nbRepl == 3 &&
7708                    iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
7709             // all bottom nodes stick: set a top before
7710             uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
7711             uniqueNodes[ 0 ] = curNodes [ 3 ];
7712             uniqueNodes[ 1 ] = curNodes [ 4 ];
7713             uniqueNodes[ 2 ] = curNodes [ 5 ];
7714           }
7715           else if (nbRepl == 4 &&
7716                    iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
7717             // a lateral face turns into a line: reverse a bottom
7718             uniqueNodes[ 0 ] = curNodes [ 1 ];
7719             uniqueNodes[ 1 ] = curNodes [ 0 ];
7720           }
7721           else
7722             isOk = false;
7723         }
7724         else if ( nbUniqueNodes == 5 ) {
7725           // PENTAHEDRON --------------------> 2 tetrahedrons
7726           if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
7727             // a bottom node sticks with a linked top one
7728             // 1.
7729             SMDS_MeshElement* newElem =
7730               aMesh->AddVolume(curNodes[ 3 ],
7731                                curNodes[ 4 ],
7732                                curNodes[ 5 ],
7733                                curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
7734             myLastCreatedElems.Append(newElem);
7735             if ( aShapeId )
7736               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7737             // 2. : reverse a bottom
7738             uniqueNodes[ 0 ] = curNodes [ 1 ];
7739             uniqueNodes[ 1 ] = curNodes [ 0 ];
7740             nbUniqueNodes = 4;
7741           }
7742           else
7743             isOk = false;
7744         }
7745         else
7746           isOk = false;
7747         break;
7748       case 8: {
7749         if(elem->IsQuadratic()) { // Quadratic quadrangle
7750           //   1    5    2
7751           //    +---+---+
7752           //    |       |
7753           //    |       |
7754           //   4+       +6
7755           //    |       |
7756           //    |       |
7757           //    +---+---+
7758           //   0    7    3
7759           isOk = false;
7760           if(nbRepl==2) {
7761             MESSAGE("nbRepl=2: " << iRepl[0] << " " << iRepl[1]);
7762           }
7763           if(nbRepl==3) {
7764             MESSAGE("nbRepl=3: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2]);
7765             nbUniqueNodes = 6;
7766             if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
7767               uniqueNodes[0] = curNodes[0];
7768               uniqueNodes[1] = curNodes[2];
7769               uniqueNodes[2] = curNodes[3];
7770               uniqueNodes[3] = curNodes[5];
7771               uniqueNodes[4] = curNodes[6];
7772               uniqueNodes[5] = curNodes[7];
7773               isOk = true;
7774             }
7775             if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
7776               uniqueNodes[0] = curNodes[0];
7777               uniqueNodes[1] = curNodes[1];
7778               uniqueNodes[2] = curNodes[2];
7779               uniqueNodes[3] = curNodes[4];
7780               uniqueNodes[4] = curNodes[5];
7781               uniqueNodes[5] = curNodes[6];
7782               isOk = true;
7783             }
7784             if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
7785               uniqueNodes[0] = curNodes[1];
7786               uniqueNodes[1] = curNodes[2];
7787               uniqueNodes[2] = curNodes[3];
7788               uniqueNodes[3] = curNodes[5];
7789               uniqueNodes[4] = curNodes[6];
7790               uniqueNodes[5] = curNodes[0];
7791               isOk = true;
7792             }
7793             if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
7794               uniqueNodes[0] = curNodes[0];
7795               uniqueNodes[1] = curNodes[1];
7796               uniqueNodes[2] = curNodes[3];
7797               uniqueNodes[3] = curNodes[4];
7798               uniqueNodes[4] = curNodes[6];
7799               uniqueNodes[5] = curNodes[7];
7800               isOk = true;
7801             }
7802             if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
7803               uniqueNodes[0] = curNodes[0];
7804               uniqueNodes[1] = curNodes[2];
7805               uniqueNodes[2] = curNodes[3];
7806               uniqueNodes[3] = curNodes[1];
7807               uniqueNodes[4] = curNodes[6];
7808               uniqueNodes[5] = curNodes[7];
7809               isOk = true;
7810             }
7811             if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
7812               uniqueNodes[0] = curNodes[0];
7813               uniqueNodes[1] = curNodes[1];
7814               uniqueNodes[2] = curNodes[2];
7815               uniqueNodes[3] = curNodes[4];
7816               uniqueNodes[4] = curNodes[5];
7817               uniqueNodes[5] = curNodes[7];
7818               isOk = true;
7819             }
7820             if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
7821               uniqueNodes[0] = curNodes[0];
7822               uniqueNodes[1] = curNodes[1];
7823               uniqueNodes[2] = curNodes[3];
7824               uniqueNodes[3] = curNodes[4];
7825               uniqueNodes[4] = curNodes[2];
7826               uniqueNodes[5] = curNodes[7];
7827               isOk = true;
7828             }
7829             if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
7830               uniqueNodes[0] = curNodes[0];
7831               uniqueNodes[1] = curNodes[1];
7832               uniqueNodes[2] = curNodes[2];
7833               uniqueNodes[3] = curNodes[4];
7834               uniqueNodes[4] = curNodes[5];
7835               uniqueNodes[5] = curNodes[3];
7836               isOk = true;
7837             }
7838           }
7839           if(nbRepl==4) {
7840             MESSAGE("nbRepl=4: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2] << " " << iRepl[3]);
7841           }
7842           if(nbRepl==5) {
7843             MESSAGE("nbRepl=5: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2] << " " << iRepl[3] << " " << iRepl[4]);
7844           }
7845           break;
7846         }
7847         //////////////////////////////////// HEXAHEDRON
7848         isOk = false;
7849         SMDS_VolumeTool hexa (elem);
7850         hexa.SetExternalNormal();
7851         if ( nbUniqueNodes == 4 && nbRepl == 4 ) {
7852           //////////////////////// HEX ---> 1 tetrahedron
7853           for ( int iFace = 0; iFace < 6; iFace++ ) {
7854             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7855             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7856                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7857                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7858               // one face turns into a point ...
7859               int iOppFace = hexa.GetOppFaceIndex( iFace );
7860               ind = hexa.GetFaceNodesIndices( iOppFace );
7861               int nbStick = 0;
7862               for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
7863                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7864                   nbStick++;
7865               }
7866               if ( nbStick == 1 ) {
7867                 // ... and the opposite one - into a triangle.
7868                 // set a top node
7869                 ind = hexa.GetFaceNodesIndices( iFace );
7870                 uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
7871                 isOk = true;
7872               }
7873               break;
7874             }
7875           }
7876         }
7877         else if ( nbUniqueNodes == 6 && nbRepl == 2 ) {
7878           //////////////////////// HEX ---> 1 prism
7879           int nbTria = 0, iTria[3];
7880           const int *ind; // indices of face nodes
7881           // look for triangular faces
7882           for ( int iFace = 0; iFace < 6 && nbTria < 3; iFace++ ) {
7883             ind = hexa.GetFaceNodesIndices( iFace );
7884             TIDSortedNodeSet faceNodes;
7885             for ( iCur = 0; iCur < 4; iCur++ )
7886               faceNodes.insert( curNodes[ind[iCur]] );
7887             if ( faceNodes.size() == 3 )
7888               iTria[ nbTria++ ] = iFace;
7889           }
7890           // check if triangles are opposite
7891           if ( nbTria == 2 && iTria[0] == hexa.GetOppFaceIndex( iTria[1] ))
7892           {
7893             isOk = true;
7894             // set nodes of the bottom triangle
7895             ind = hexa.GetFaceNodesIndices( iTria[ 0 ]);
7896             vector<int> indB;
7897             for ( iCur = 0; iCur < 4; iCur++ )
7898               if ( ind[iCur] != iRepl[0] && ind[iCur] != iRepl[1])
7899                 indB.push_back( ind[iCur] );
7900             if ( !hexa.IsForward() )
7901               std::swap( indB[0], indB[2] );
7902             for ( iCur = 0; iCur < 3; iCur++ )
7903               uniqueNodes[ iCur ] = curNodes[indB[iCur]];
7904             // set nodes of the top triangle
7905             const int *indT = hexa.GetFaceNodesIndices( iTria[ 1 ]);
7906             for ( iCur = 0; iCur < 3; ++iCur )
7907               for ( int j = 0; j < 4; ++j )
7908                 if ( hexa.IsLinked( indB[ iCur ], indT[ j ] ))
7909                 {
7910                   uniqueNodes[ iCur + 3 ] = curNodes[ indT[ j ]];
7911                   break;
7912                 }
7913           }
7914           break;
7915         }
7916         else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
7917           //////////////////// HEXAHEDRON ---> 2 tetrahedrons
7918           for ( int iFace = 0; iFace < 6; iFace++ ) {
7919             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7920             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7921                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7922                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7923               // one face turns into a point ...
7924               int iOppFace = hexa.GetOppFaceIndex( iFace );
7925               ind = hexa.GetFaceNodesIndices( iOppFace );
7926               int nbStick = 0;
7927               iUnique = 2;  // reverse a tetrahedron 1 bottom
7928               for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
7929                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7930                   nbStick++;
7931                 else if ( iUnique >= 0 )
7932                   uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7933               }
7934               if ( nbStick == 0 ) {
7935                 // ... and the opposite one is a quadrangle
7936                 // set a top node
7937                 const int* indTop = hexa.GetFaceNodesIndices( iFace );
7938                 uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
7939                 nbUniqueNodes = 4;
7940                 // tetrahedron 2
7941                 SMDS_MeshElement* newElem =
7942                   aMesh->AddVolume(curNodes[ind[ 0 ]],
7943                                    curNodes[ind[ 3 ]],
7944                                    curNodes[ind[ 2 ]],
7945                                    curNodes[indTop[ 0 ]]);
7946                 myLastCreatedElems.Append(newElem);
7947                 if ( aShapeId )
7948                   aMesh->SetMeshElementOnShape( newElem, aShapeId );
7949                 isOk = true;
7950               }
7951               break;
7952             }
7953           }
7954         }
7955         else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
7956           ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
7957           // find indices of quad and tri faces
7958           int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
7959           for ( iFace = 0; iFace < 6; iFace++ ) {
7960             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7961             nodeSet.clear();
7962             for ( iCur = 0; iCur < 4; iCur++ )
7963               nodeSet.insert( curNodes[ind[ iCur ]] );
7964             nbUniqueNodes = nodeSet.size();
7965             if ( nbUniqueNodes == 3 )
7966               iTriFace[ nbTri++ ] = iFace;
7967             else if ( nbUniqueNodes == 4 )
7968               iQuadFace[ nbQuad++ ] = iFace;
7969           }
7970           if (nbQuad == 2 && nbTri == 4 &&
7971               hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
7972             // 2 opposite quadrangles stuck with a diagonal;
7973             // sample groups of merged indices: (0-4)(2-6)
7974             // --------------------------------------------> 2 tetrahedrons
7975             const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
7976             const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
7977             int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
7978             if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
7979                 curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
7980               // stuck with 0-2 diagonal
7981               i0  = ind1[ 3 ];
7982               i1d = ind1[ 0 ];
7983               i2  = ind1[ 1 ];
7984               i3d = ind1[ 2 ];
7985               i0t = ind2[ 1 ];
7986               i2t = ind2[ 3 ];
7987             }
7988             else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
7989                      curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
7990               // stuck with 1-3 diagonal
7991               i0  = ind1[ 0 ];
7992               i1d = ind1[ 1 ];
7993               i2  = ind1[ 2 ];
7994               i3d = ind1[ 3 ];
7995               i0t = ind2[ 0 ];
7996               i2t = ind2[ 1 ];
7997             }
7998             else {
7999               ASSERT(0);
8000             }
8001             // tetrahedron 1
8002             uniqueNodes[ 0 ] = curNodes [ i0 ];
8003             uniqueNodes[ 1 ] = curNodes [ i1d ];
8004             uniqueNodes[ 2 ] = curNodes [ i3d ];
8005             uniqueNodes[ 3 ] = curNodes [ i0t ];
8006             nbUniqueNodes = 4;
8007             // tetrahedron 2
8008             SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
8009                                                          curNodes[ i2 ],
8010                                                          curNodes[ i3d ],
8011                                                          curNodes[ i2t ]);
8012             myLastCreatedElems.Append(newElem);
8013             if ( aShapeId )
8014               aMesh->SetMeshElementOnShape( newElem, aShapeId );
8015             isOk = true;
8016           }
8017           else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
8018                    ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
8019             // --------------------------------------------> prism
8020             // find 2 opposite triangles
8021             nbUniqueNodes = 6;
8022             for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
8023               if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
8024                 // find indices of kept and replaced nodes
8025                 // and fill unique nodes of 2 opposite triangles
8026                 const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
8027                 const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
8028                 const SMDS_MeshNode** hexanodes = hexa.GetNodes();
8029                 // fill unique nodes
8030                 iUnique = 0;
8031                 isOk = true;
8032                 for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
8033                   const SMDS_MeshNode* n     = curNodes[ind1[ iCur ]];
8034                   const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
8035                   if ( n == nInit ) {
8036                     // iCur of a linked node of the opposite face (make normals co-directed):
8037                     int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
8038                     // check that correspondent corners of triangles are linked
8039                     if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
8040                       isOk = false;
8041                     else {
8042                       uniqueNodes[ iUnique ] = n;
8043                       uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
8044                       iUnique++;
8045                     }
8046                   }
8047                 }
8048                 break;
8049               }
8050             }
8051           }
8052         } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
8053         else
8054         {
8055           MESSAGE("MergeNodes() removes hexahedron "<< elem);
8056         }
8057         break;
8058       } // HEXAHEDRON
8059
8060       default:
8061         isOk = false;
8062       } // switch ( nbNodes )
8063
8064     } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
8065
8066     if ( isOk ) { // the elem remains valid after sticking nodes
8067       if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume)
8068       {
8069         // Change nodes of polyedre
8070         const SMDS_VtkVolume* aPolyedre =
8071           dynamic_cast<const SMDS_VtkVolume*>( elem );
8072         if (aPolyedre) {
8073           int nbFaces = aPolyedre->NbFaces();
8074
8075           vector<const SMDS_MeshNode *> poly_nodes;
8076           vector<int> quantities (nbFaces);
8077
8078           for (int iface = 1; iface <= nbFaces; iface++) {
8079             int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
8080             quantities[iface - 1] = nbFaceNodes;
8081
8082             for (inode = 1; inode <= nbFaceNodes; inode++) {
8083               const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
8084
8085               TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
8086               if (nnIt != nodeNodeMap.end()) { // curNode sticks
8087                 curNode = (*nnIt).second;
8088               }
8089               poly_nodes.push_back(curNode);
8090             }
8091           }
8092           aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
8093         }
8094       }
8095       else // replace non-polyhedron elements
8096       {
8097         const SMDSAbs_ElementType etyp = elem->GetType();
8098         const int elemId               = elem->GetID();
8099         const bool isPoly              = (elem->GetEntityType() == SMDSEntity_Polygon);
8100         uniqueNodes.resize(nbUniqueNodes);
8101
8102         SMESHDS_SubMesh * sm = aShapeId > 0 ? aMesh->MeshElements(aShapeId) : 0;
8103
8104         aMesh->RemoveFreeElement(elem, sm, /*fromGroups=*/false);
8105         SMDS_MeshElement* newElem = this->AddElement(uniqueNodes, etyp, isPoly, elemId);
8106         if ( sm && newElem )
8107           sm->AddElement( newElem );
8108         if ( elem != newElem )
8109           ReplaceElemInGroups( elem, newElem, aMesh );
8110       }
8111     }
8112     else {
8113       // Remove invalid regular element or invalid polygon
8114       rmElemIds.push_back( elem->GetID() );
8115     }
8116
8117   } // loop on elements
8118
8119   // Remove bad elements, then equal nodes (order important)
8120
8121   Remove( rmElemIds, false );
8122   Remove( rmNodeIds, true );
8123
8124 }
8125
8126
8127 // ========================================================
8128 // class   : SortableElement
8129 // purpose : allow sorting elements basing on their nodes
8130 // ========================================================
8131 class SortableElement : public set <const SMDS_MeshElement*>
8132 {
8133 public:
8134
8135   SortableElement( const SMDS_MeshElement* theElem )
8136   {
8137     myElem = theElem;
8138     SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
8139     while ( nodeIt->more() )
8140       this->insert( nodeIt->next() );
8141   }
8142
8143   const SMDS_MeshElement* Get() const
8144   { return myElem; }
8145
8146   void Set(const SMDS_MeshElement* e) const
8147   { myElem = e; }
8148
8149
8150 private:
8151   mutable const SMDS_MeshElement* myElem;
8152 };
8153
8154 //=======================================================================
8155 //function : FindEqualElements
8156 //purpose  : Return list of group of elements built on the same nodes.
8157 //           Search among theElements or in the whole mesh if theElements is empty
8158 //=======================================================================
8159 void SMESH_MeshEditor::FindEqualElements(set<const SMDS_MeshElement*> & theElements,
8160                                          TListOfListOfElementsID &      theGroupsOfElementsID)
8161 {
8162   myLastCreatedElems.Clear();
8163   myLastCreatedNodes.Clear();
8164
8165   typedef set<const SMDS_MeshElement*> TElemsSet;
8166   typedef map< SortableElement, int > TMapOfNodeSet;
8167   typedef list<int> TGroupOfElems;
8168
8169   TElemsSet elems;
8170   if ( theElements.empty() )
8171   { // get all elements in the mesh
8172     SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
8173     while ( eIt->more() )
8174       elems.insert( elems.end(), eIt->next());
8175   }
8176   else
8177     elems = theElements;
8178
8179   vector< TGroupOfElems > arrayOfGroups;
8180   TGroupOfElems groupOfElems;
8181   TMapOfNodeSet mapOfNodeSet;
8182
8183   TElemsSet::iterator elemIt = elems.begin();
8184   for ( int i = 0, j=0; elemIt != elems.end(); ++elemIt, ++j ) {
8185     const SMDS_MeshElement* curElem = *elemIt;
8186     SortableElement SE(curElem);
8187     int ind = -1;
8188     // check uniqueness
8189     pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
8190     if( !(pp.second) ) {
8191       TMapOfNodeSet::iterator& itSE = pp.first;
8192       ind = (*itSE).second;
8193       arrayOfGroups[ind].push_back(curElem->GetID());
8194     }
8195     else {
8196       groupOfElems.clear();
8197       groupOfElems.push_back(curElem->GetID());
8198       arrayOfGroups.push_back(groupOfElems);
8199       i++;
8200     }
8201   }
8202
8203   vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
8204   for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
8205     groupOfElems = *groupIt;
8206     if ( groupOfElems.size() > 1 ) {
8207       groupOfElems.sort();
8208       theGroupsOfElementsID.push_back(groupOfElems);
8209     }
8210   }
8211 }
8212
8213 //=======================================================================
8214 //function : MergeElements
8215 //purpose  : In each given group, substitute all elements by the first one.
8216 //=======================================================================
8217
8218 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
8219 {
8220   myLastCreatedElems.Clear();
8221   myLastCreatedNodes.Clear();
8222
8223   typedef list<int> TListOfIDs;
8224   TListOfIDs rmElemIds; // IDs of elems to remove
8225
8226   SMESHDS_Mesh* aMesh = GetMeshDS();
8227
8228   TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
8229   while ( groupsIt != theGroupsOfElementsID.end() ) {
8230     TListOfIDs& aGroupOfElemID = *groupsIt;
8231     aGroupOfElemID.sort();
8232     int elemIDToKeep = aGroupOfElemID.front();
8233     const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
8234     aGroupOfElemID.pop_front();
8235     TListOfIDs::iterator idIt = aGroupOfElemID.begin();
8236     while ( idIt != aGroupOfElemID.end() ) {
8237       int elemIDToRemove = *idIt;
8238       const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
8239       // add the kept element in groups of removed one (PAL15188)
8240       AddToSameGroups( elemToKeep, elemToRemove, aMesh );
8241       rmElemIds.push_back( elemIDToRemove );
8242       ++idIt;
8243     }
8244     ++groupsIt;
8245   }
8246
8247   Remove( rmElemIds, false );
8248 }
8249
8250 //=======================================================================
8251 //function : MergeEqualElements
8252 //purpose  : Remove all but one of elements built on the same nodes.
8253 //=======================================================================
8254
8255 void SMESH_MeshEditor::MergeEqualElements()
8256 {
8257   set<const SMDS_MeshElement*> aMeshElements; /* empty input -
8258                                                  to merge equal elements in the whole mesh */
8259   TListOfListOfElementsID aGroupsOfElementsID;
8260   FindEqualElements(aMeshElements, aGroupsOfElementsID);
8261   MergeElements(aGroupsOfElementsID);
8262 }
8263
8264 //=======================================================================
8265 //function : FindFaceInSet
8266 //purpose  : Return a face having linked nodes n1 and n2 and which is
8267 //           - not in avoidSet,
8268 //           - in elemSet provided that !elemSet.empty()
8269 //           i1 and i2 optionally returns indices of n1 and n2
8270 //=======================================================================
8271
8272 const SMDS_MeshElement*
8273 SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode*    n1,
8274                                 const SMDS_MeshNode*    n2,
8275                                 const TIDSortedElemSet& elemSet,
8276                                 const TIDSortedElemSet& avoidSet,
8277                                 int*                    n1ind,
8278                                 int*                    n2ind)
8279
8280 {
8281   int i1, i2;
8282   const SMDS_MeshElement* face = 0;
8283
8284   SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face);
8285   //MESSAGE("n1->GetInverseElementIterator(SMDSAbs_Face) " << invElemIt);
8286   while ( invElemIt->more() && !face ) // loop on inverse faces of n1
8287   {
8288     //MESSAGE("in while ( invElemIt->more() && !face )");
8289     const SMDS_MeshElement* elem = invElemIt->next();
8290     if (avoidSet.count( elem ))
8291       continue;
8292     if ( !elemSet.empty() && !elemSet.count( elem ))
8293       continue;
8294     // index of n1
8295     i1 = elem->GetNodeIndex( n1 );
8296     // find a n2 linked to n1
8297     int nbN = elem->IsQuadratic() ? elem->NbNodes()/2 : elem->NbNodes();
8298     for ( int di = -1; di < 2 && !face; di += 2 )
8299     {
8300       i2 = (i1+di+nbN) % nbN;
8301       if ( elem->GetNode( i2 ) == n2 )
8302         face = elem;
8303     }
8304     if ( !face && elem->IsQuadratic())
8305     {
8306       // analysis for quadratic elements using all nodes
8307       const SMDS_VtkFace* F =
8308         dynamic_cast<const SMDS_VtkFace*>(elem);
8309       if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8310       // use special nodes iterator
8311       SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8312       const SMDS_MeshNode* prevN = cast2Node( anIter->next() );
8313       for ( i1 = -1, i2 = 0; anIter->more() && !face; i1++, i2++ )
8314       {
8315         const SMDS_MeshNode* n = cast2Node( anIter->next() );
8316         if ( n1 == prevN && n2 == n )
8317         {
8318           face = elem;
8319         }
8320         else if ( n2 == prevN && n1 == n )
8321         {
8322           face = elem; swap( i1, i2 );
8323         }
8324         prevN = n;
8325       }
8326     }
8327   }
8328   if ( n1ind ) *n1ind = i1;
8329   if ( n2ind ) *n2ind = i2;
8330   return face;
8331 }
8332
8333 //=======================================================================
8334 //function : findAdjacentFace
8335 //purpose  :
8336 //=======================================================================
8337
8338 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
8339                                                 const SMDS_MeshNode* n2,
8340                                                 const SMDS_MeshElement* elem)
8341 {
8342   TIDSortedElemSet elemSet, avoidSet;
8343   if ( elem )
8344     avoidSet.insert ( elem );
8345   return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet );
8346 }
8347
8348 //=======================================================================
8349 //function : FindFreeBorder
8350 //purpose  :
8351 //=======================================================================
8352
8353 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
8354
8355 bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode*             theFirstNode,
8356                                        const SMDS_MeshNode*             theSecondNode,
8357                                        const SMDS_MeshNode*             theLastNode,
8358                                        list< const SMDS_MeshNode* > &   theNodes,
8359                                        list< const SMDS_MeshElement* >& theFaces)
8360 {
8361   if ( !theFirstNode || !theSecondNode )
8362     return false;
8363   // find border face between theFirstNode and theSecondNode
8364   const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
8365   if ( !curElem )
8366     return false;
8367
8368   theFaces.push_back( curElem );
8369   theNodes.push_back( theFirstNode );
8370   theNodes.push_back( theSecondNode );
8371
8372   //vector<const SMDS_MeshNode*> nodes;
8373   const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
8374   TIDSortedElemSet foundElems;
8375   bool needTheLast = ( theLastNode != 0 );
8376
8377   while ( nStart != theLastNode ) {
8378     if ( nStart == theFirstNode )
8379       return !needTheLast;
8380
8381     // find all free border faces sharing form nStart
8382
8383     list< const SMDS_MeshElement* > curElemList;
8384     list< const SMDS_MeshNode* > nStartList;
8385     SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
8386     while ( invElemIt->more() ) {
8387       const SMDS_MeshElement* e = invElemIt->next();
8388       if ( e == curElem || foundElems.insert( e ).second ) {
8389         // get nodes
8390         int iNode = 0, nbNodes = e->NbNodes();
8391         //const SMDS_MeshNode* nodes[nbNodes+1];
8392         vector<const SMDS_MeshNode*> nodes(nbNodes+1);
8393
8394         if(e->IsQuadratic()) {
8395           const SMDS_VtkFace* F =
8396             dynamic_cast<const SMDS_VtkFace*>(e);
8397           if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8398           // use special nodes iterator
8399           SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8400           while( anIter->more() ) {
8401             nodes[ iNode++ ] = cast2Node(anIter->next());
8402           }
8403         }
8404         else {
8405           SMDS_ElemIteratorPtr nIt = e->nodesIterator();
8406           while ( nIt->more() )
8407             nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
8408         }
8409         nodes[ iNode ] = nodes[ 0 ];
8410         // check 2 links
8411         for ( iNode = 0; iNode < nbNodes; iNode++ )
8412           if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
8413                (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
8414               ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
8415           {
8416             nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
8417             curElemList.push_back( e );
8418           }
8419       }
8420     }
8421     // analyse the found
8422
8423     int nbNewBorders = curElemList.size();
8424     if ( nbNewBorders == 0 ) {
8425       // no free border furthermore
8426       return !needTheLast;
8427     }
8428     else if ( nbNewBorders == 1 ) {
8429       // one more element found
8430       nIgnore = nStart;
8431       nStart = nStartList.front();
8432       curElem = curElemList.front();
8433       theFaces.push_back( curElem );
8434       theNodes.push_back( nStart );
8435     }
8436     else {
8437       // several continuations found
8438       list< const SMDS_MeshElement* >::iterator curElemIt;
8439       list< const SMDS_MeshNode* >::iterator nStartIt;
8440       // check if one of them reached the last node
8441       if ( needTheLast ) {
8442         for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
8443              curElemIt!= curElemList.end();
8444              curElemIt++, nStartIt++ )
8445           if ( *nStartIt == theLastNode ) {
8446             theFaces.push_back( *curElemIt );
8447             theNodes.push_back( *nStartIt );
8448             return true;
8449           }
8450       }
8451       // find the best free border by the continuations
8452       list<const SMDS_MeshNode*>    contNodes[ 2 ], *cNL;
8453       list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
8454       for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
8455            curElemIt!= curElemList.end();
8456            curElemIt++, nStartIt++ )
8457       {
8458         cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
8459         cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
8460         // find one more free border
8461         if ( ! FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
8462           cNL->clear();
8463           cFL->clear();
8464         }
8465         else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
8466           // choice: clear a worse one
8467           int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
8468           int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
8469           contNodes[ iWorse ].clear();
8470           contFaces[ iWorse ].clear();
8471         }
8472       }
8473       if ( contNodes[0].empty() && contNodes[1].empty() )
8474         return false;
8475
8476       // append the best free border
8477       cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
8478       cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
8479       theNodes.pop_back(); // remove nIgnore
8480       theNodes.pop_back(); // remove nStart
8481       theFaces.pop_back(); // remove curElem
8482       list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
8483       list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
8484       for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
8485       for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
8486       return true;
8487
8488     } // several continuations found
8489   } // while ( nStart != theLastNode )
8490
8491   return true;
8492 }
8493
8494 //=======================================================================
8495 //function : CheckFreeBorderNodes
8496 //purpose  : Return true if the tree nodes are on a free border
8497 //=======================================================================
8498
8499 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
8500                                             const SMDS_MeshNode* theNode2,
8501                                             const SMDS_MeshNode* theNode3)
8502 {
8503   list< const SMDS_MeshNode* > nodes;
8504   list< const SMDS_MeshElement* > faces;
8505   return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
8506 }
8507
8508 //=======================================================================
8509 //function : SewFreeBorder
8510 //purpose  :
8511 //=======================================================================
8512
8513 SMESH_MeshEditor::Sew_Error
8514 SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
8515                                  const SMDS_MeshNode* theBordSecondNode,
8516                                  const SMDS_MeshNode* theBordLastNode,
8517                                  const SMDS_MeshNode* theSideFirstNode,
8518                                  const SMDS_MeshNode* theSideSecondNode,
8519                                  const SMDS_MeshNode* theSideThirdNode,
8520                                  const bool           theSideIsFreeBorder,
8521                                  const bool           toCreatePolygons,
8522                                  const bool           toCreatePolyedrs)
8523 {
8524   myLastCreatedElems.Clear();
8525   myLastCreatedNodes.Clear();
8526
8527   MESSAGE("::SewFreeBorder()");
8528   Sew_Error aResult = SEW_OK;
8529
8530   // ====================================
8531   //    find side nodes and elements
8532   // ====================================
8533
8534   list< const SMDS_MeshNode* > nSide[ 2 ];
8535   list< const SMDS_MeshElement* > eSide[ 2 ];
8536   list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
8537   list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
8538
8539   // Free border 1
8540   // --------------
8541   if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
8542                       nSide[0], eSide[0])) {
8543     MESSAGE(" Free Border 1 not found " );
8544     aResult = SEW_BORDER1_NOT_FOUND;
8545   }
8546   if (theSideIsFreeBorder) {
8547     // Free border 2
8548     // --------------
8549     if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
8550                         nSide[1], eSide[1])) {
8551       MESSAGE(" Free Border 2 not found " );
8552       aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
8553     }
8554   }
8555   if ( aResult != SEW_OK )
8556     return aResult;
8557
8558   if (!theSideIsFreeBorder) {
8559     // Side 2
8560     // --------------
8561
8562     // -------------------------------------------------------------------------
8563     // Algo:
8564     // 1. If nodes to merge are not coincident, move nodes of the free border
8565     //    from the coord sys defined by the direction from the first to last
8566     //    nodes of the border to the correspondent sys of the side 2
8567     // 2. On the side 2, find the links most co-directed with the correspondent
8568     //    links of the free border
8569     // -------------------------------------------------------------------------
8570
8571     // 1. Since sewing may break if there are volumes to split on the side 2,
8572     //    we wont move nodes but just compute new coordinates for them
8573     typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
8574     TNodeXYZMap nBordXYZ;
8575     list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
8576     list< const SMDS_MeshNode* >::iterator nBordIt;
8577
8578     gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
8579     gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
8580     gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
8581     gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
8582     double tol2 = 1.e-8;
8583     gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
8584     if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
8585       // Need node movement.
8586
8587       // find X and Z axes to create trsf
8588       gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
8589       gp_Vec X = Zs ^ Zb;
8590       if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
8591         // Zb || Zs
8592         X = gp_Ax2( gp::Origin(), Zb ).XDirection();
8593
8594       // coord systems
8595       gp_Ax3 toBordAx( Pb1, Zb, X );
8596       gp_Ax3 fromSideAx( Ps1, Zs, X );
8597       gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
8598       // set trsf
8599       gp_Trsf toBordSys, fromSide2Sys;
8600       toBordSys.SetTransformation( toBordAx );
8601       fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
8602       fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
8603
8604       // move
8605       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8606         const SMDS_MeshNode* n = *nBordIt;
8607         gp_XYZ xyz( n->X(),n->Y(),n->Z() );
8608         toBordSys.Transforms( xyz );
8609         fromSide2Sys.Transforms( xyz );
8610         nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
8611       }
8612     }
8613     else {
8614       // just insert nodes XYZ in the nBordXYZ map
8615       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8616         const SMDS_MeshNode* n = *nBordIt;
8617         nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
8618       }
8619     }
8620
8621     // 2. On the side 2, find the links most co-directed with the correspondent
8622     //    links of the free border
8623
8624     list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
8625     list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
8626     sideNodes.push_back( theSideFirstNode );
8627
8628     bool hasVolumes = false;
8629     LinkID_Gen aLinkID_Gen( GetMeshDS() );
8630     set<long> foundSideLinkIDs, checkedLinkIDs;
8631     SMDS_VolumeTool volume;
8632     //const SMDS_MeshNode* faceNodes[ 4 ];
8633
8634     const SMDS_MeshNode*    sideNode;
8635     const SMDS_MeshElement* sideElem;
8636     const SMDS_MeshNode* prevSideNode = theSideFirstNode;
8637     const SMDS_MeshNode* prevBordNode = theBordFirstNode;
8638     nBordIt = bordNodes.begin();
8639     nBordIt++;
8640     // border node position and border link direction to compare with
8641     gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
8642     gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
8643     // choose next side node by link direction or by closeness to
8644     // the current border node:
8645     bool searchByDir = ( *nBordIt != theBordLastNode );
8646     do {
8647       // find the next node on the Side 2
8648       sideNode = 0;
8649       double maxDot = -DBL_MAX, minDist = DBL_MAX;
8650       long linkID;
8651       checkedLinkIDs.clear();
8652       gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
8653
8654       // loop on inverse elements of current node (prevSideNode) on the Side 2
8655       SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
8656       while ( invElemIt->more() )
8657       {
8658         const SMDS_MeshElement* elem = invElemIt->next();
8659         // prepare data for a loop on links coming to prevSideNode, of a face or a volume
8660         int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
8661         vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
8662         bool isVolume = volume.Set( elem );
8663         const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
8664         if ( isVolume ) // --volume
8665           hasVolumes = true;
8666         else if ( elem->GetType()==SMDSAbs_Face ) { // --face
8667           // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
8668           if(elem->IsQuadratic()) {
8669             const SMDS_VtkFace* F =
8670               dynamic_cast<const SMDS_VtkFace*>(elem);
8671             if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8672             // use special nodes iterator
8673             SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8674             while( anIter->more() ) {
8675               nodes[ iNode ] = cast2Node(anIter->next());
8676               if ( nodes[ iNode++ ] == prevSideNode )
8677                 iPrevNode = iNode - 1;
8678             }
8679           }
8680           else {
8681             SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
8682             while ( nIt->more() ) {
8683               nodes[ iNode ] = cast2Node( nIt->next() );
8684               if ( nodes[ iNode++ ] == prevSideNode )
8685                 iPrevNode = iNode - 1;
8686             }
8687           }
8688           // there are 2 links to check
8689           nbNodes = 2;
8690         }
8691         else // --edge
8692           continue;
8693         // loop on links, to be precise, on the second node of links
8694         for ( iNode = 0; iNode < nbNodes; iNode++ ) {
8695           const SMDS_MeshNode* n = nodes[ iNode ];
8696           if ( isVolume ) {
8697             if ( !volume.IsLinked( n, prevSideNode ))
8698               continue;
8699           }
8700           else {
8701             if ( iNode ) // a node before prevSideNode
8702               n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
8703             else         // a node after prevSideNode
8704               n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
8705           }
8706           // check if this link was already used
8707           long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
8708           bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
8709           if (!isJustChecked &&
8710               foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
8711           {
8712             // test a link geometrically
8713             gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
8714             bool linkIsBetter = false;
8715             double dot = 0.0, dist = 0.0;
8716             if ( searchByDir ) { // choose most co-directed link
8717               dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
8718               linkIsBetter = ( dot > maxDot );
8719             }
8720             else { // choose link with the node closest to bordPos
8721               dist = ( nextXYZ - bordPos ).SquareModulus();
8722               linkIsBetter = ( dist < minDist );
8723             }
8724             if ( linkIsBetter ) {
8725               maxDot = dot;
8726               minDist = dist;
8727               linkID = iLink;
8728               sideNode = n;
8729               sideElem = elem;
8730             }
8731           }
8732         }
8733       } // loop on inverse elements of prevSideNode
8734
8735       if ( !sideNode ) {
8736         MESSAGE(" Cant find path by links of the Side 2 ");
8737         return SEW_BAD_SIDE_NODES;
8738       }
8739       sideNodes.push_back( sideNode );
8740       sideElems.push_back( sideElem );
8741       foundSideLinkIDs.insert ( linkID );
8742       prevSideNode = sideNode;
8743
8744       if ( *nBordIt == theBordLastNode )
8745         searchByDir = false;
8746       else {
8747         // find the next border link to compare with
8748         gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
8749         searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8750         // move to next border node if sideNode is before forward border node (bordPos)
8751         while ( *nBordIt != theBordLastNode && !searchByDir ) {
8752           prevBordNode = *nBordIt;
8753           nBordIt++;
8754           bordPos = nBordXYZ[ *nBordIt ];
8755           bordDir = bordPos - nBordXYZ[ prevBordNode ];
8756           searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8757         }
8758       }
8759     }
8760     while ( sideNode != theSideSecondNode );
8761
8762     if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
8763       MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
8764       return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
8765     }
8766   } // end nodes search on the side 2
8767
8768   // ============================
8769   // sew the border to the side 2
8770   // ============================
8771
8772   int nbNodes[]  = { nSide[0].size(), nSide[1].size() };
8773   int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
8774
8775   TListOfListOfNodes nodeGroupsToMerge;
8776   if ( nbNodes[0] == nbNodes[1] ||
8777        ( theSideIsFreeBorder && !theSideThirdNode)) {
8778
8779     // all nodes are to be merged
8780
8781     for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
8782          nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
8783          nIt[0]++, nIt[1]++ )
8784     {
8785       nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8786       nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
8787       nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
8788     }
8789   }
8790   else {
8791
8792     // insert new nodes into the border and the side to get equal nb of segments
8793
8794     // get normalized parameters of nodes on the borders
8795     //double param[ 2 ][ maxNbNodes ];
8796     double* param[ 2 ];
8797     param[0] = new double [ maxNbNodes ];
8798     param[1] = new double [ maxNbNodes ];
8799     int iNode, iBord;
8800     for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8801       list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
8802       list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
8803       const SMDS_MeshNode* nPrev = *nIt;
8804       double bordLength = 0;
8805       for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
8806         const SMDS_MeshNode* nCur = *nIt;
8807         gp_XYZ segment (nCur->X() - nPrev->X(),
8808                         nCur->Y() - nPrev->Y(),
8809                         nCur->Z() - nPrev->Z());
8810         double segmentLen = segment.Modulus();
8811         bordLength += segmentLen;
8812         param[ iBord ][ iNode ] = bordLength;
8813         nPrev = nCur;
8814       }
8815       // normalize within [0,1]
8816       for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
8817         param[ iBord ][ iNode ] /= bordLength;
8818       }
8819     }
8820
8821     // loop on border segments
8822     const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
8823     int i[ 2 ] = { 0, 0 };
8824     nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
8825     nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
8826
8827     TElemOfNodeListMap insertMap;
8828     TElemOfNodeListMap::iterator insertMapIt;
8829     // insertMap is
8830     // key:   elem to insert nodes into
8831     // value: 2 nodes to insert between + nodes to be inserted
8832     do {
8833       bool next[ 2 ] = { false, false };
8834
8835       // find min adjacent segment length after sewing
8836       double nextParam = 10., prevParam = 0;
8837       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8838         if ( i[ iBord ] + 1 < nbNodes[ iBord ])
8839           nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
8840         if ( i[ iBord ] > 0 )
8841           prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
8842       }
8843       double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8844       double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8845       double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
8846
8847       // choose to insert or to merge nodes
8848       double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
8849       if ( Abs( du ) <= minSegLen * 0.2 ) {
8850         // merge
8851         // ------
8852         nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8853         const SMDS_MeshNode* n0 = *nIt[0];
8854         const SMDS_MeshNode* n1 = *nIt[1];
8855         nodeGroupsToMerge.back().push_back( n1 );
8856         nodeGroupsToMerge.back().push_back( n0 );
8857         // position of node of the border changes due to merge
8858         param[ 0 ][ i[0] ] += du;
8859         // move n1 for the sake of elem shape evaluation during insertion.
8860         // n1 will be removed by MergeNodes() anyway
8861         const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
8862         next[0] = next[1] = true;
8863       }
8864       else {
8865         // insert
8866         // ------
8867         int intoBord = ( du < 0 ) ? 0 : 1;
8868         const SMDS_MeshElement* elem = *eIt[ intoBord ];
8869         const SMDS_MeshNode*    n1   = nPrev[ intoBord ];
8870         const SMDS_MeshNode*    n2   = *nIt[ intoBord ];
8871         const SMDS_MeshNode*    nIns = *nIt[ 1 - intoBord ];
8872         if ( intoBord == 1 ) {
8873           // move node of the border to be on a link of elem of the side
8874           gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
8875           gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
8876           double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
8877           gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
8878           GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
8879         }
8880         insertMapIt = insertMap.find( elem );
8881         bool notFound = ( insertMapIt == insertMap.end() );
8882         bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
8883         if ( otherLink ) {
8884           // insert into another link of the same element:
8885           // 1. perform insertion into the other link of the elem
8886           list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8887           const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
8888           const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
8889           InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
8890           // 2. perform insertion into the link of adjacent faces
8891           while (true) {
8892             const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
8893             if ( adjElem )
8894               InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
8895             else
8896               break;
8897           }
8898           if (toCreatePolyedrs) {
8899             // perform insertion into the links of adjacent volumes
8900             UpdateVolumes(n12, n22, nodeList);
8901           }
8902           // 3. find an element appeared on n1 and n2 after the insertion
8903           insertMap.erase( elem );
8904           elem = findAdjacentFace( n1, n2, 0 );
8905         }
8906         if ( notFound || otherLink ) {
8907           // add element and nodes of the side into the insertMap
8908           insertMapIt = insertMap.insert
8909             ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
8910           (*insertMapIt).second.push_back( n1 );
8911           (*insertMapIt).second.push_back( n2 );
8912         }
8913         // add node to be inserted into elem
8914         (*insertMapIt).second.push_back( nIns );
8915         next[ 1 - intoBord ] = true;
8916       }
8917
8918       // go to the next segment
8919       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8920         if ( next[ iBord ] ) {
8921           if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
8922             eIt[ iBord ]++;
8923           nPrev[ iBord ] = *nIt[ iBord ];
8924           nIt[ iBord ]++; i[ iBord ]++;
8925         }
8926       }
8927     }
8928     while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
8929
8930     // perform insertion of nodes into elements
8931
8932     for (insertMapIt = insertMap.begin();
8933          insertMapIt != insertMap.end();
8934          insertMapIt++ )
8935     {
8936       const SMDS_MeshElement* elem = (*insertMapIt).first;
8937       list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8938       const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
8939       const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
8940
8941       InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
8942
8943       if ( !theSideIsFreeBorder ) {
8944         // look for and insert nodes into the faces adjacent to elem
8945         while (true) {
8946           const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
8947           if ( adjElem )
8948             InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
8949           else
8950             break;
8951         }
8952       }
8953       if (toCreatePolyedrs) {
8954         // perform insertion into the links of adjacent volumes
8955         UpdateVolumes(n1, n2, nodeList);
8956       }
8957     }
8958
8959     delete param[0];
8960     delete param[1];
8961   } // end: insert new nodes
8962
8963   MergeNodes ( nodeGroupsToMerge );
8964
8965   return aResult;
8966 }
8967
8968 //=======================================================================
8969 //function : InsertNodesIntoLink
8970 //purpose  : insert theNodesToInsert into theFace between theBetweenNode1
8971 //           and theBetweenNode2 and split theElement
8972 //=======================================================================
8973
8974 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement*     theFace,
8975                                            const SMDS_MeshNode*        theBetweenNode1,
8976                                            const SMDS_MeshNode*        theBetweenNode2,
8977                                            list<const SMDS_MeshNode*>& theNodesToInsert,
8978                                            const bool                  toCreatePoly)
8979 {
8980   if ( theFace->GetType() != SMDSAbs_Face ) return;
8981
8982   // find indices of 2 link nodes and of the rest nodes
8983   int iNode = 0, il1, il2, i3, i4;
8984   il1 = il2 = i3 = i4 = -1;
8985   //const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
8986   vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
8987
8988   if(theFace->IsQuadratic()) {
8989     const SMDS_VtkFace* F =
8990       dynamic_cast<const SMDS_VtkFace*>(theFace);
8991     if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8992     // use special nodes iterator
8993     SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8994     while( anIter->more() ) {
8995       const SMDS_MeshNode* n = cast2Node(anIter->next());
8996       if ( n == theBetweenNode1 )
8997         il1 = iNode;
8998       else if ( n == theBetweenNode2 )
8999         il2 = iNode;
9000       else if ( i3 < 0 )
9001         i3 = iNode;
9002       else
9003         i4 = iNode;
9004       nodes[ iNode++ ] = n;
9005     }
9006   }
9007   else {
9008     SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
9009     while ( nodeIt->more() ) {
9010       const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9011       if ( n == theBetweenNode1 )
9012         il1 = iNode;
9013       else if ( n == theBetweenNode2 )
9014         il2 = iNode;
9015       else if ( i3 < 0 )
9016         i3 = iNode;
9017       else
9018         i4 = iNode;
9019       nodes[ iNode++ ] = n;
9020     }
9021   }
9022   if ( il1 < 0 || il2 < 0 || i3 < 0 )
9023     return ;
9024
9025   // arrange link nodes to go one after another regarding the face orientation
9026   bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
9027   list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
9028   if ( reverse ) {
9029     iNode = il1;
9030     il1 = il2;
9031     il2 = iNode;
9032     aNodesToInsert.reverse();
9033   }
9034   // check that not link nodes of a quadrangles are in good order
9035   int nbFaceNodes = theFace->NbNodes();
9036   if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
9037     iNode = i3;
9038     i3 = i4;
9039     i4 = iNode;
9040   }
9041
9042   if (toCreatePoly || theFace->IsPoly()) {
9043
9044     iNode = 0;
9045     vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
9046
9047     // add nodes of face up to first node of link
9048     bool isFLN = false;
9049
9050     if(theFace->IsQuadratic()) {
9051       const SMDS_VtkFace* F =
9052         dynamic_cast<const SMDS_VtkFace*>(theFace);
9053       if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
9054       // use special nodes iterator
9055       SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
9056       while( anIter->more()  && !isFLN ) {
9057         const SMDS_MeshNode* n = cast2Node(anIter->next());
9058         poly_nodes[iNode++] = n;
9059         if (n == nodes[il1]) {
9060           isFLN = true;
9061         }
9062       }
9063       // add nodes to insert
9064       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
9065       for (; nIt != aNodesToInsert.end(); nIt++) {
9066         poly_nodes[iNode++] = *nIt;
9067       }
9068       // add nodes of face starting from last node of link
9069       while ( anIter->more() ) {
9070         poly_nodes[iNode++] = cast2Node(anIter->next());
9071       }
9072     }
9073     else {
9074       SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
9075       while ( nodeIt->more() && !isFLN ) {
9076         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9077         poly_nodes[iNode++] = n;
9078         if (n == nodes[il1]) {
9079           isFLN = true;
9080         }
9081       }
9082       // add nodes to insert
9083       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
9084       for (; nIt != aNodesToInsert.end(); nIt++) {
9085         poly_nodes[iNode++] = *nIt;
9086       }
9087       // add nodes of face starting from last node of link
9088       while ( nodeIt->more() ) {
9089         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9090         poly_nodes[iNode++] = n;
9091       }
9092     }
9093
9094     // edit or replace the face
9095     SMESHDS_Mesh *aMesh = GetMeshDS();
9096
9097     if (theFace->IsPoly()) {
9098       aMesh->ChangePolygonNodes(theFace, poly_nodes);
9099     }
9100     else {
9101       int aShapeId = FindShape( theFace );
9102
9103       SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
9104       myLastCreatedElems.Append(newElem);
9105       if ( aShapeId && newElem )
9106         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9107
9108       aMesh->RemoveElement(theFace);
9109     }
9110     return;
9111   }
9112
9113   SMESHDS_Mesh *aMesh = GetMeshDS();
9114   if( !theFace->IsQuadratic() ) {
9115
9116     // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
9117     int nbLinkNodes = 2 + aNodesToInsert.size();
9118     //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
9119     vector<const SMDS_MeshNode*> linkNodes( nbLinkNodes );
9120     linkNodes[ 0 ] = nodes[ il1 ];
9121     linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
9122     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
9123     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
9124       linkNodes[ iNode++ ] = *nIt;
9125     }
9126     // decide how to split a quadrangle: compare possible variants
9127     // and choose which of splits to be a quadrangle
9128     int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
9129     if ( nbFaceNodes == 3 ) {
9130       iBestQuad = nbSplits;
9131       i4 = i3;
9132     }
9133     else if ( nbFaceNodes == 4 ) {
9134       SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
9135       double aBestRate = DBL_MAX;
9136       for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
9137         i1 = 0; i2 = 1;
9138         double aBadRate = 0;
9139         // evaluate elements quality
9140         for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
9141           if ( iSplit == iQuad ) {
9142             SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
9143                                    linkNodes[ i2++ ],
9144                                    nodes[ i3 ],
9145                                    nodes[ i4 ]);
9146             aBadRate += getBadRate( &quad, aCrit );
9147           }
9148           else {
9149             SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
9150                                    linkNodes[ i2++ ],
9151                                    nodes[ iSplit < iQuad ? i4 : i3 ]);
9152             aBadRate += getBadRate( &tria, aCrit );
9153           }
9154         }
9155         // choice
9156         if ( aBadRate < aBestRate ) {
9157           iBestQuad = iQuad;
9158           aBestRate = aBadRate;
9159         }
9160       }
9161     }
9162
9163     // create new elements
9164     int aShapeId = FindShape( theFace );
9165
9166     i1 = 0; i2 = 1;
9167     for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
9168       SMDS_MeshElement* newElem = 0;
9169       if ( iSplit == iBestQuad )
9170         newElem = aMesh->AddFace (linkNodes[ i1++ ],
9171                                   linkNodes[ i2++ ],
9172                                   nodes[ i3 ],
9173                                   nodes[ i4 ]);
9174       else
9175         newElem = aMesh->AddFace (linkNodes[ i1++ ],
9176                                   linkNodes[ i2++ ],
9177                                   nodes[ iSplit < iBestQuad ? i4 : i3 ]);
9178       myLastCreatedElems.Append(newElem);
9179       if ( aShapeId && newElem )
9180         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9181     }
9182
9183     // change nodes of theFace
9184     const SMDS_MeshNode* newNodes[ 4 ];
9185     newNodes[ 0 ] = linkNodes[ i1 ];
9186     newNodes[ 1 ] = linkNodes[ i2 ];
9187     newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
9188     newNodes[ 3 ] = nodes[ i4 ];
9189     //aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
9190     const SMDS_MeshElement* newElem = 0;
9191     if (iSplit == iBestQuad)
9192       newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2], newNodes[3] );
9193     else
9194       newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2] );
9195     myLastCreatedElems.Append(newElem);
9196     if ( aShapeId && newElem )
9197       aMesh->SetMeshElementOnShape( newElem, aShapeId );
9198 } // end if(!theFace->IsQuadratic())
9199   else { // theFace is quadratic
9200     // we have to split theFace on simple triangles and one simple quadrangle
9201     int tmp = il1/2;
9202     int nbshift = tmp*2;
9203     // shift nodes in nodes[] by nbshift
9204     int i,j;
9205     for(i=0; i<nbshift; i++) {
9206       const SMDS_MeshNode* n = nodes[0];
9207       for(j=0; j<nbFaceNodes-1; j++) {
9208         nodes[j] = nodes[j+1];
9209       }
9210       nodes[nbFaceNodes-1] = n;
9211     }
9212     il1 = il1 - nbshift;
9213     // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
9214     //   n0      n1     n2    n0      n1     n2
9215     //     +-----+-----+        +-----+-----+
9216     //      \         /         |           |
9217     //       \       /          |           |
9218     //      n5+     +n3       n7+           +n3
9219     //         \   /            |           |
9220     //          \ /             |           |
9221     //           +              +-----+-----+
9222     //           n4           n6      n5     n4
9223
9224     // create new elements
9225     int aShapeId = FindShape( theFace );
9226
9227     int n1,n2,n3;
9228     if(nbFaceNodes==6) { // quadratic triangle
9229       SMDS_MeshElement* newElem =
9230         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
9231       myLastCreatedElems.Append(newElem);
9232       if ( aShapeId && newElem )
9233         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9234       if(theFace->IsMediumNode(nodes[il1])) {
9235         // create quadrangle
9236         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
9237         myLastCreatedElems.Append(newElem);
9238         if ( aShapeId && newElem )
9239           aMesh->SetMeshElementOnShape( newElem, aShapeId );
9240         n1 = 1;
9241         n2 = 2;
9242         n3 = 3;
9243       }
9244       else {
9245         // create quadrangle
9246         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
9247         myLastCreatedElems.Append(newElem);
9248         if ( aShapeId && newElem )
9249           aMesh->SetMeshElementOnShape( newElem, aShapeId );
9250         n1 = 0;
9251         n2 = 1;
9252         n3 = 5;
9253       }
9254     }
9255     else { // nbFaceNodes==8 - quadratic quadrangle
9256       SMDS_MeshElement* newElem =
9257         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
9258       myLastCreatedElems.Append(newElem);
9259       if ( aShapeId && newElem )
9260         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9261       newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
9262       myLastCreatedElems.Append(newElem);
9263       if ( aShapeId && newElem )
9264         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9265       newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
9266       myLastCreatedElems.Append(newElem);
9267       if ( aShapeId && newElem )
9268         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9269       if(theFace->IsMediumNode(nodes[il1])) {
9270         // create quadrangle
9271         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
9272         myLastCreatedElems.Append(newElem);
9273         if ( aShapeId && newElem )
9274           aMesh->SetMeshElementOnShape( newElem, aShapeId );
9275         n1 = 1;
9276         n2 = 2;
9277         n3 = 3;
9278       }
9279       else {
9280         // create quadrangle
9281         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
9282         myLastCreatedElems.Append(newElem);
9283         if ( aShapeId && newElem )
9284           aMesh->SetMeshElementOnShape( newElem, aShapeId );
9285         n1 = 0;
9286         n2 = 1;
9287         n3 = 7;
9288       }
9289     }
9290     // create needed triangles using n1,n2,n3 and inserted nodes
9291     int nbn = 2 + aNodesToInsert.size();
9292     //const SMDS_MeshNode* aNodes[nbn];
9293     vector<const SMDS_MeshNode*> aNodes(nbn);
9294     aNodes[0] = nodes[n1];
9295     aNodes[nbn-1] = nodes[n2];
9296     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
9297     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
9298       aNodes[iNode++] = *nIt;
9299     }
9300     for(i=1; i<nbn; i++) {
9301       SMDS_MeshElement* newElem =
9302         aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
9303       myLastCreatedElems.Append(newElem);
9304       if ( aShapeId && newElem )
9305         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9306     }
9307   }
9308   // remove old face
9309   aMesh->RemoveElement(theFace);
9310 }
9311
9312 //=======================================================================
9313 //function : UpdateVolumes
9314 //purpose  :
9315 //=======================================================================
9316 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode*        theBetweenNode1,
9317                                       const SMDS_MeshNode*        theBetweenNode2,
9318                                       list<const SMDS_MeshNode*>& theNodesToInsert)
9319 {
9320   myLastCreatedElems.Clear();
9321   myLastCreatedNodes.Clear();
9322
9323   SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
9324   while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
9325     const SMDS_MeshElement* elem = invElemIt->next();
9326
9327     // check, if current volume has link theBetweenNode1 - theBetweenNode2
9328     SMDS_VolumeTool aVolume (elem);
9329     if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
9330       continue;
9331
9332     // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
9333     int iface, nbFaces = aVolume.NbFaces();
9334     vector<const SMDS_MeshNode *> poly_nodes;
9335     vector<int> quantities (nbFaces);
9336
9337     for (iface = 0; iface < nbFaces; iface++) {
9338       int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
9339       // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
9340       const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
9341
9342       for (int inode = 0; inode < nbFaceNodes; inode++) {
9343         poly_nodes.push_back(faceNodes[inode]);
9344
9345         if (nbInserted == 0) {
9346           if (faceNodes[inode] == theBetweenNode1) {
9347             if (faceNodes[inode + 1] == theBetweenNode2) {
9348               nbInserted = theNodesToInsert.size();
9349
9350               // add nodes to insert
9351               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
9352               for (; nIt != theNodesToInsert.end(); nIt++) {
9353                 poly_nodes.push_back(*nIt);
9354               }
9355             }
9356           }
9357           else if (faceNodes[inode] == theBetweenNode2) {
9358             if (faceNodes[inode + 1] == theBetweenNode1) {
9359               nbInserted = theNodesToInsert.size();
9360
9361               // add nodes to insert in reversed order
9362               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
9363               nIt--;
9364               for (; nIt != theNodesToInsert.begin(); nIt--) {
9365                 poly_nodes.push_back(*nIt);
9366               }
9367               poly_nodes.push_back(*nIt);
9368             }
9369           }
9370           else {
9371           }
9372         }
9373       }
9374       quantities[iface] = nbFaceNodes + nbInserted;
9375     }
9376
9377     // Replace or update the volume
9378     SMESHDS_Mesh *aMesh = GetMeshDS();
9379
9380     if (elem->IsPoly()) {
9381       aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
9382
9383     }
9384     else {
9385       int aShapeId = FindShape( elem );
9386
9387       SMDS_MeshElement* newElem =
9388         aMesh->AddPolyhedralVolume(poly_nodes, quantities);
9389       myLastCreatedElems.Append(newElem);
9390       if (aShapeId && newElem)
9391         aMesh->SetMeshElementOnShape(newElem, aShapeId);
9392
9393       aMesh->RemoveElement(elem);
9394     }
9395   }
9396 }
9397
9398 namespace
9399 {
9400   //================================================================================
9401   /*!
9402    * \brief Transform any volume into data of SMDSEntity_Polyhedra
9403    */
9404   //================================================================================
9405
9406   void volumeToPolyhedron( const SMDS_MeshElement*         elem,
9407                            vector<const SMDS_MeshNode *> & nodes,
9408                            vector<int> &                   nbNodeInFaces )
9409   {
9410     nodes.clear();
9411     nbNodeInFaces.clear();
9412     SMDS_VolumeTool vTool ( elem );
9413     for ( int iF = 0; iF < vTool.NbFaces(); ++iF )
9414     {
9415       const SMDS_MeshNode** fNodes = vTool.GetFaceNodes( iF );
9416       nodes.insert( nodes.end(), fNodes, fNodes + vTool.NbFaceNodes( iF ));
9417       nbNodeInFaces.push_back( vTool.NbFaceNodes( iF ));
9418     }
9419   }
9420 }
9421
9422 //=======================================================================
9423 /*!
9424  * \brief Convert elements contained in a submesh to quadratic
9425  * \return int - nb of checked elements
9426  */
9427 //=======================================================================
9428
9429 int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh *   theSm,
9430                                              SMESH_MesherHelper& theHelper,
9431                                              const bool          theForce3d)
9432 {
9433   int nbElem = 0;
9434   if( !theSm ) return nbElem;
9435
9436   vector<int> nbNodeInFaces;
9437   vector<const SMDS_MeshNode *> nodes;
9438   SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
9439   while(ElemItr->more())
9440   {
9441     nbElem++;
9442     const SMDS_MeshElement* elem = ElemItr->next();
9443     if( !elem || elem->IsQuadratic() ) continue;
9444
9445     // get elem data needed to re-create it
9446     //
9447     const int id                        = elem->GetID();
9448     const int nbNodes                   = elem->NbNodes();
9449     const SMDSAbs_ElementType aType     = elem->GetType();
9450     const SMDSAbs_EntityType  aGeomType = elem->GetEntityType();
9451     nodes.assign(elem->begin_nodes(), elem->end_nodes());
9452     if ( aGeomType == SMDSEntity_Polyhedra )
9453       nbNodeInFaces = static_cast<const SMDS_VtkVolume* >( elem )->GetQuantities();
9454     else if ( aGeomType == SMDSEntity_Hexagonal_Prism )
9455       volumeToPolyhedron( elem, nodes, nbNodeInFaces );
9456
9457     // remove a linear element
9458     GetMeshDS()->RemoveFreeElement(elem, theSm, /*fromGroups=*/false);
9459
9460     const SMDS_MeshElement* NewElem = 0;
9461
9462     switch( aType )
9463     {
9464     case SMDSAbs_Edge :
9465       {
9466         NewElem = theHelper.AddEdge(nodes[0], nodes[1], id, theForce3d);
9467         break;
9468       }
9469     case SMDSAbs_Face :
9470       {
9471         switch(nbNodes)
9472         {
9473         case 3:
9474           NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
9475           break;
9476         case 4:
9477           NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9478           break;
9479         default:
9480           NewElem = theHelper.AddPolygonalFace(nodes, id, theForce3d);
9481           continue;
9482         }
9483         break;
9484       }
9485     case SMDSAbs_Volume :
9486       {
9487         switch( aGeomType )
9488         {
9489         case SMDSEntity_Tetra:
9490           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9491           break;
9492         case SMDSEntity_Pyramid:
9493           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], id, theForce3d);
9494           break;
9495         case SMDSEntity_Penta:
9496           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], nodes[5], id, theForce3d);
9497           break;
9498         case SMDSEntity_Hexa:
9499           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9500                                         nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9501           break;
9502         case SMDSEntity_Hexagonal_Prism:
9503         default:
9504           NewElem = theHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9505         }
9506         break;
9507       }
9508     default :
9509       continue;
9510     }
9511     ReplaceElemInGroups( elem, NewElem, GetMeshDS());
9512     if( NewElem )
9513       theSm->AddElement( NewElem );
9514   }
9515   return nbElem;
9516 }
9517
9518 //=======================================================================
9519 //function : ConvertToQuadratic
9520 //purpose  :
9521 //=======================================================================
9522
9523 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
9524 {
9525   SMESHDS_Mesh* meshDS = GetMeshDS();
9526
9527   SMESH_MesherHelper aHelper(*myMesh);
9528   aHelper.SetIsQuadratic( true );
9529
9530   int nbCheckedElems = 0;
9531   if ( myMesh->HasShapeToMesh() )
9532   {
9533     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9534     {
9535       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9536       while ( smIt->more() ) {
9537         SMESH_subMesh* sm = smIt->next();
9538         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
9539           aHelper.SetSubShape( sm->GetSubShape() );
9540           nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
9541         }
9542       }
9543     }
9544   }
9545   int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
9546   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9547   {
9548     SMESHDS_SubMesh *smDS = 0;
9549     SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
9550     while(aEdgeItr->more())
9551     {
9552       const SMDS_MeshEdge* edge = aEdgeItr->next();
9553       if(edge && !edge->IsQuadratic())
9554       {
9555         int id = edge->GetID();
9556         //MESSAGE("edge->GetID() " << id);
9557         const SMDS_MeshNode* n1 = edge->GetNode(0);
9558         const SMDS_MeshNode* n2 = edge->GetNode(1);
9559
9560         meshDS->RemoveFreeElement(edge, smDS, /*fromGroups=*/false);
9561
9562         const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
9563         ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
9564       }
9565     }
9566     SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
9567     while(aFaceItr->more())
9568     {
9569       const SMDS_MeshFace* face = aFaceItr->next();
9570       if(!face || face->IsQuadratic() ) continue;
9571
9572       const int id = face->GetID();
9573       const SMDSAbs_EntityType type = face->GetEntityType();
9574       vector<const SMDS_MeshNode *> nodes ( face->begin_nodes(), face->end_nodes());
9575
9576       meshDS->RemoveFreeElement(face, smDS, /*fromGroups=*/false);
9577
9578       SMDS_MeshFace * NewFace = 0;
9579       switch( type )
9580       {
9581       case SMDSEntity_Triangle:
9582         NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
9583         break;
9584       case SMDSEntity_Quadrangle:
9585         NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9586         break;
9587       default:
9588         NewFace = aHelper.AddPolygonalFace(nodes, id, theForce3d);
9589       }
9590       ReplaceElemInGroups( face, NewFace, GetMeshDS());
9591     }
9592     vector<int> nbNodeInFaces;
9593     SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
9594     while(aVolumeItr->more())
9595     {
9596       const SMDS_MeshVolume* volume = aVolumeItr->next();
9597       if(!volume || volume->IsQuadratic() ) continue;
9598
9599       const int id = volume->GetID();
9600       const SMDSAbs_EntityType type = volume->GetEntityType();
9601       vector<const SMDS_MeshNode *> nodes (volume->begin_nodes(), volume->end_nodes());
9602       if ( type == SMDSEntity_Polyhedra )
9603         nbNodeInFaces = static_cast<const SMDS_VtkVolume* >(volume)->GetQuantities();
9604       else if ( type == SMDSEntity_Hexagonal_Prism )
9605         volumeToPolyhedron( volume, nodes, nbNodeInFaces );
9606
9607       meshDS->RemoveFreeElement(volume, smDS, /*fromGroups=*/false);
9608
9609       SMDS_MeshVolume * NewVolume = 0;
9610       switch ( type )
9611       {
9612       case SMDSEntity_Tetra:
9613         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d );
9614         break;
9615       case SMDSEntity_Hexa:
9616         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9617                                       nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9618         break;
9619       case SMDSEntity_Pyramid:
9620         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9621                                       nodes[3], nodes[4], id, theForce3d);
9622         break;
9623       case SMDSEntity_Penta:
9624         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9625                                       nodes[3], nodes[4], nodes[5], id, theForce3d);
9626         break;
9627       case SMDSEntity_Hexagonal_Prism:
9628       default:
9629         NewVolume = aHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9630       }
9631       ReplaceElemInGroups(volume, NewVolume, meshDS);
9632     }
9633   }
9634
9635   if ( !theForce3d )
9636   { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
9637     aHelper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
9638     aHelper.FixQuadraticElements(myError);
9639   }
9640 }
9641
9642 //================================================================================
9643 /*!
9644  * \brief Makes given elements quadratic
9645  *  \param theForce3d - if true, the medium nodes will be placed in the middle of link
9646  *  \param theElements - elements to make quadratic
9647  */
9648 //================================================================================
9649
9650 void SMESH_MeshEditor::ConvertToQuadratic(const bool        theForce3d,
9651                                           TIDSortedElemSet& theElements)
9652 {
9653   if ( theElements.empty() ) return;
9654
9655   // we believe that all theElements are of the same type
9656   const SMDSAbs_ElementType elemType = (*theElements.begin())->GetType();
9657
9658   // get all nodes shared by theElements
9659   TIDSortedNodeSet allNodes;
9660   TIDSortedElemSet::iterator eIt = theElements.begin();
9661   for ( ; eIt != theElements.end(); ++eIt )
9662     allNodes.insert( (*eIt)->begin_nodes(), (*eIt)->end_nodes() );
9663
9664   // complete theElements with elements of lower dim whose all nodes are in allNodes
9665
9666   TIDSortedElemSet quadAdjacentElems    [ SMDSAbs_NbElementTypes ]; // quadratic adjacent elements
9667   TIDSortedElemSet checkedAdjacentElems [ SMDSAbs_NbElementTypes ];
9668   TIDSortedNodeSet::iterator nIt = allNodes.begin();
9669   for ( ; nIt != allNodes.end(); ++nIt )
9670   {
9671     const SMDS_MeshNode* n = *nIt;
9672     SMDS_ElemIteratorPtr invIt = n->GetInverseElementIterator();
9673     while ( invIt->more() )
9674     {
9675       const SMDS_MeshElement* e = invIt->next();
9676       if ( e->IsQuadratic() )
9677       {
9678         quadAdjacentElems[ e->GetType() ].insert( e );
9679         continue;
9680       }
9681       if ( e->GetType() >= elemType )
9682       {
9683         continue; // same type of more complex linear element
9684       }
9685
9686       if ( !checkedAdjacentElems[ e->GetType() ].insert( e ).second )
9687         continue; // e is already checked
9688
9689       // check nodes
9690       bool allIn = true;
9691       SMDS_ElemIteratorPtr nodeIt = e->nodesIterator();
9692       while ( nodeIt->more() && allIn )
9693         allIn = allNodes.count( cast2Node( nodeIt->next() ));
9694       if ( allIn )
9695         theElements.insert(e );
9696     }
9697   }
9698
9699   SMESH_MesherHelper helper(*myMesh);
9700   helper.SetIsQuadratic( true );
9701
9702   // add links of quadratic adjacent elements to the helper
9703
9704   if ( !quadAdjacentElems[SMDSAbs_Edge].empty() )
9705     for ( eIt  = quadAdjacentElems[SMDSAbs_Edge].begin();
9706           eIt != quadAdjacentElems[SMDSAbs_Edge].end(); ++eIt )
9707     {
9708       helper.AddTLinks( static_cast< const SMDS_MeshEdge*> (*eIt) );
9709     }
9710   if ( !quadAdjacentElems[SMDSAbs_Face].empty() )
9711     for ( eIt  = quadAdjacentElems[SMDSAbs_Face].begin();
9712           eIt != quadAdjacentElems[SMDSAbs_Face].end(); ++eIt )
9713     {
9714       helper.AddTLinks( static_cast< const SMDS_MeshFace*> (*eIt) );
9715     }
9716   if ( !quadAdjacentElems[SMDSAbs_Volume].empty() )
9717     for ( eIt  = quadAdjacentElems[SMDSAbs_Volume].begin();
9718           eIt != quadAdjacentElems[SMDSAbs_Volume].end(); ++eIt )
9719     {
9720       helper.AddTLinks( static_cast< const SMDS_MeshVolume*> (*eIt) );
9721     }
9722
9723   // make quadratic elements instead of linear ones
9724
9725   SMESHDS_Mesh* meshDS = GetMeshDS();
9726   SMESHDS_SubMesh* smDS = 0;
9727   for ( eIt = theElements.begin(); eIt != theElements.end(); ++eIt )
9728   {
9729     const SMDS_MeshElement* elem = *eIt;
9730     if( elem->IsQuadratic() || elem->NbNodes() < 2 || elem->IsPoly() )
9731       continue;
9732
9733     const int id                   = elem->GetID();
9734     const SMDSAbs_ElementType type = elem->GetType();
9735     vector<const SMDS_MeshNode *> nodes ( elem->begin_nodes(), elem->end_nodes());
9736
9737     if ( !smDS || !smDS->Contains( elem ))
9738       smDS = meshDS->MeshElements( elem->getshapeId() );
9739     meshDS->RemoveFreeElement(elem, smDS, /*fromGroups=*/false);
9740
9741     SMDS_MeshElement * newElem = 0;
9742     switch( nodes.size() )
9743     {
9744     case 4: // cases for most frequently used element types go first (for optimization)
9745       if ( type == SMDSAbs_Volume )
9746         newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9747       else
9748         newElem = helper.AddFace  (nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9749       break;
9750     case 8:
9751       newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9752                                  nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9753       break;
9754     case 3:
9755       newElem = helper.AddFace  (nodes[0], nodes[1], nodes[2], id, theForce3d);
9756       break;
9757     case 2:
9758       newElem = helper.AddEdge(nodes[0], nodes[1], id, theForce3d);
9759       break;
9760     case 5:
9761       newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9762                                  nodes[4], id, theForce3d);
9763       break;
9764     case 6:
9765       newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9766                                  nodes[4], nodes[5], id, theForce3d);
9767       break;
9768     default:;
9769     }
9770     ReplaceElemInGroups( elem, newElem, meshDS);
9771     if( newElem && smDS )
9772       smDS->AddElement( newElem );
9773   }
9774
9775   if ( !theForce3d  && !getenv("NO_FixQuadraticElements"))
9776   { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
9777     helper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
9778     helper.FixQuadraticElements( myError );
9779   }
9780 }
9781
9782 //=======================================================================
9783 /*!
9784  * \brief Convert quadratic elements to linear ones and remove quadratic nodes
9785  * \return int - nb of checked elements
9786  */
9787 //=======================================================================
9788
9789 int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh *    theSm,
9790                                      SMDS_ElemIteratorPtr theItr,
9791                                      const int            theShapeID)
9792 {
9793   int nbElem = 0;
9794   SMESHDS_Mesh* meshDS = GetMeshDS();
9795
9796   while( theItr->more() )
9797   {
9798     const SMDS_MeshElement* elem = theItr->next();
9799     nbElem++;
9800     if( elem && elem->IsQuadratic())
9801     {
9802       int id                    = elem->GetID();
9803       int nbCornerNodes         = elem->NbCornerNodes();
9804       SMDSAbs_ElementType aType = elem->GetType();
9805
9806       vector<const SMDS_MeshNode *> nodes( elem->begin_nodes(), elem->end_nodes() );
9807
9808       //remove a quadratic element
9809       if ( !theSm || !theSm->Contains( elem ))
9810         theSm = meshDS->MeshElements( elem->getshapeId() );
9811       meshDS->RemoveFreeElement( elem, theSm, /*fromGroups=*/false );
9812
9813       // remove medium nodes
9814       for ( unsigned i = nbCornerNodes; i < nodes.size(); ++i )
9815         if ( nodes[i]->NbInverseElements() == 0 )
9816           meshDS->RemoveFreeNode( nodes[i], theSm );
9817
9818       // add a linear element
9819       nodes.resize( nbCornerNodes );
9820       SMDS_MeshElement * newElem = AddElement( nodes, aType, false, id );
9821       ReplaceElemInGroups(elem, newElem, meshDS);
9822       if( theSm && newElem )
9823         theSm->AddElement( newElem );
9824     }
9825   }
9826   return nbElem;
9827 }
9828
9829 //=======================================================================
9830 //function : ConvertFromQuadratic
9831 //purpose  :
9832 //=======================================================================
9833
9834 bool SMESH_MeshEditor::ConvertFromQuadratic()
9835 {
9836   int nbCheckedElems = 0;
9837   if ( myMesh->HasShapeToMesh() )
9838   {
9839     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9840     {
9841       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9842       while ( smIt->more() ) {
9843         SMESH_subMesh* sm = smIt->next();
9844         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
9845           nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
9846       }
9847     }
9848   }
9849
9850   int totalNbElems =
9851     GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
9852   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9853   {
9854     SMESHDS_SubMesh *aSM = 0;
9855     removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
9856   }
9857
9858   return true;
9859 }
9860
9861 namespace
9862 {
9863   //================================================================================
9864   /*!
9865    * \brief Return true if all medium nodes of the element are in the node set
9866    */
9867   //================================================================================
9868
9869   bool allMediumNodesIn(const SMDS_MeshElement* elem, TIDSortedNodeSet& nodeSet )
9870   {
9871     for ( int i = elem->NbCornerNodes(); i < elem->NbNodes(); ++i )
9872       if ( !nodeSet.count( elem->GetNode(i) ))
9873         return false;
9874     return true;
9875   }
9876 }
9877
9878 //================================================================================
9879 /*!
9880  * \brief Makes given elements linear
9881  */
9882 //================================================================================
9883
9884 void SMESH_MeshEditor::ConvertFromQuadratic(TIDSortedElemSet& theElements)
9885 {
9886   if ( theElements.empty() ) return;
9887
9888   // collect IDs of medium nodes of theElements; some of these nodes will be removed
9889   set<int> mediumNodeIDs;
9890   TIDSortedElemSet::iterator eIt = theElements.begin();
9891   for ( ; eIt != theElements.end(); ++eIt )
9892   {
9893     const SMDS_MeshElement* e = *eIt;
9894     for ( int i = e->NbCornerNodes(); i < e->NbNodes(); ++i )
9895       mediumNodeIDs.insert( e->GetNode(i)->GetID() );
9896   }
9897
9898   // replace given elements by linear ones
9899   typedef SMDS_SetIterator<const SMDS_MeshElement*, TIDSortedElemSet::iterator> TSetIterator;
9900   SMDS_ElemIteratorPtr elemIt( new TSetIterator( theElements.begin(), theElements.end() ));
9901   removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
9902
9903   // we need to convert remaining elements whose all medium nodes are in mediumNodeIDs
9904   // except those elements sharing medium nodes of quadratic element whose medium nodes
9905   // are not all in mediumNodeIDs
9906
9907   // get remaining medium nodes
9908   TIDSortedNodeSet mediumNodes;
9909   set<int>::iterator nIdsIt = mediumNodeIDs.begin();
9910   for ( ; nIdsIt != mediumNodeIDs.end(); ++nIdsIt )
9911     if ( const SMDS_MeshNode* n = GetMeshDS()->FindNode( *nIdsIt ))
9912       mediumNodes.insert( mediumNodes.end(), n );
9913
9914   // find more quadratic elements to convert
9915   TIDSortedElemSet moreElemsToConvert;
9916   TIDSortedNodeSet::iterator nIt = mediumNodes.begin();
9917   for ( ; nIt != mediumNodes.end(); ++nIt )
9918   {
9919     SMDS_ElemIteratorPtr invIt = (*nIt)->GetInverseElementIterator();
9920     while ( invIt->more() )
9921     {
9922       const SMDS_MeshElement* e = invIt->next();
9923       if ( e->IsQuadratic() && allMediumNodesIn( e, mediumNodes ))
9924       {
9925         // find a more complex element including e and
9926         // whose medium nodes are not in mediumNodes
9927         bool complexFound = false;
9928         for ( int type = e->GetType() + 1; type < SMDSAbs_0DElement; ++type )
9929         {
9930           SMDS_ElemIteratorPtr invIt2 =
9931             (*nIt)->GetInverseElementIterator( SMDSAbs_ElementType( type ));
9932           while ( invIt2->more() )
9933           {
9934             const SMDS_MeshElement* eComplex = invIt2->next();
9935             if ( eComplex->IsQuadratic() && !allMediumNodesIn( eComplex, mediumNodes))
9936             {
9937               int nbCommonNodes = SMESH_Algo::GetCommonNodes( e, eComplex ).size();
9938               if ( nbCommonNodes == e->NbNodes())
9939               {
9940                 complexFound = true;
9941                 type = SMDSAbs_NbElementTypes; // to quit from the outer loop
9942                 break;
9943               }
9944             }
9945           }
9946         }
9947         if ( !complexFound )
9948           moreElemsToConvert.insert( e );
9949       }
9950     }
9951   }
9952   elemIt = SMDS_ElemIteratorPtr
9953     (new TSetIterator( moreElemsToConvert.begin(), moreElemsToConvert.end() ));
9954   removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
9955 }
9956
9957 //=======================================================================
9958 //function : SewSideElements
9959 //purpose  :
9960 //=======================================================================
9961
9962 SMESH_MeshEditor::Sew_Error
9963 SMESH_MeshEditor::SewSideElements (TIDSortedElemSet&    theSide1,
9964                                    TIDSortedElemSet&    theSide2,
9965                                    const SMDS_MeshNode* theFirstNode1,
9966                                    const SMDS_MeshNode* theFirstNode2,
9967                                    const SMDS_MeshNode* theSecondNode1,
9968                                    const SMDS_MeshNode* theSecondNode2)
9969 {
9970   myLastCreatedElems.Clear();
9971   myLastCreatedNodes.Clear();
9972
9973   MESSAGE ("::::SewSideElements()");
9974   if ( theSide1.size() != theSide2.size() )
9975     return SEW_DIFF_NB_OF_ELEMENTS;
9976
9977   Sew_Error aResult = SEW_OK;
9978   // Algo:
9979   // 1. Build set of faces representing each side
9980   // 2. Find which nodes of the side 1 to merge with ones on the side 2
9981   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9982
9983   // =======================================================================
9984   // 1. Build set of faces representing each side:
9985   // =======================================================================
9986   // a. build set of nodes belonging to faces
9987   // b. complete set of faces: find missing faces whose nodes are in set of nodes
9988   // c. create temporary faces representing side of volumes if correspondent
9989   //    face does not exist
9990
9991   SMESHDS_Mesh* aMesh = GetMeshDS();
9992   // TODO algoritm not OK with vtkUnstructuredGrid: 2 meshes can't share nodes
9993   //SMDS_Mesh aTmpFacesMesh; // try to use the same mesh
9994   TIDSortedElemSet             faceSet1, faceSet2;
9995   set<const SMDS_MeshElement*> volSet1,  volSet2;
9996   set<const SMDS_MeshNode*>    nodeSet1, nodeSet2;
9997   TIDSortedElemSet             * faceSetPtr[] = { &faceSet1, &faceSet2 };
9998   set<const SMDS_MeshElement*> *  volSetPtr[] = { &volSet1,  &volSet2  };
9999   set<const SMDS_MeshNode*>    * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
10000   TIDSortedElemSet             * elemSetPtr[] = { &theSide1, &theSide2 };
10001   int iSide, iFace, iNode;
10002
10003   list<const SMDS_MeshElement* > tempFaceList;
10004   for ( iSide = 0; iSide < 2; iSide++ ) {
10005     set<const SMDS_MeshNode*>    * nodeSet = nodeSetPtr[ iSide ];
10006     TIDSortedElemSet             * elemSet = elemSetPtr[ iSide ];
10007     TIDSortedElemSet             * faceSet = faceSetPtr[ iSide ];
10008     set<const SMDS_MeshElement*> * volSet  = volSetPtr [ iSide ];
10009     set<const SMDS_MeshElement*>::iterator vIt;
10010     TIDSortedElemSet::iterator eIt;
10011     set<const SMDS_MeshNode*>::iterator    nIt;
10012
10013     // check that given nodes belong to given elements
10014     const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
10015     const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
10016     int firstIndex = -1, secondIndex = -1;
10017     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
10018       const SMDS_MeshElement* elem = *eIt;
10019       if ( firstIndex  < 0 ) firstIndex  = elem->GetNodeIndex( n1 );
10020       if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
10021       if ( firstIndex > -1 && secondIndex > -1 ) break;
10022     }
10023     if ( firstIndex < 0 || secondIndex < 0 ) {
10024       // we can simply return until temporary faces created
10025       return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
10026     }
10027
10028     // -----------------------------------------------------------
10029     // 1a. Collect nodes of existing faces
10030     //     and build set of face nodes in order to detect missing
10031     //     faces corresponding to sides of volumes
10032     // -----------------------------------------------------------
10033
10034     set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
10035
10036     // loop on the given element of a side
10037     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
10038       //const SMDS_MeshElement* elem = *eIt;
10039       const SMDS_MeshElement* elem = *eIt;
10040       if ( elem->GetType() == SMDSAbs_Face ) {
10041         faceSet->insert( elem );
10042         set <const SMDS_MeshNode*> faceNodeSet;
10043         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
10044         while ( nodeIt->more() ) {
10045           const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
10046           nodeSet->insert( n );
10047           faceNodeSet.insert( n );
10048         }
10049         setOfFaceNodeSet.insert( faceNodeSet );
10050       }
10051       else if ( elem->GetType() == SMDSAbs_Volume )
10052         volSet->insert( elem );
10053     }
10054     // ------------------------------------------------------------------------------
10055     // 1b. Complete set of faces: find missing faces whose nodes are in set of nodes
10056     // ------------------------------------------------------------------------------
10057
10058     for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
10059       SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
10060       while ( fIt->more() ) { // loop on faces sharing a node
10061         const SMDS_MeshElement* f = fIt->next();
10062         if ( faceSet->find( f ) == faceSet->end() ) {
10063           // check if all nodes are in nodeSet and
10064           // complete setOfFaceNodeSet if they are
10065           set <const SMDS_MeshNode*> faceNodeSet;
10066           SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
10067           bool allInSet = true;
10068           while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
10069             const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
10070             if ( nodeSet->find( n ) == nodeSet->end() )
10071               allInSet = false;
10072             else
10073               faceNodeSet.insert( n );
10074           }
10075           if ( allInSet ) {
10076             faceSet->insert( f );
10077             setOfFaceNodeSet.insert( faceNodeSet );
10078           }
10079         }
10080       }
10081     }
10082
10083     // -------------------------------------------------------------------------
10084     // 1c. Create temporary faces representing sides of volumes if correspondent
10085     //     face does not exist
10086     // -------------------------------------------------------------------------
10087
10088     if ( !volSet->empty() ) {
10089       //int nodeSetSize = nodeSet->size();
10090
10091       // loop on given volumes
10092       for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
10093         SMDS_VolumeTool vol (*vIt);
10094         // loop on volume faces: find free faces
10095         // --------------------------------------
10096         list<const SMDS_MeshElement* > freeFaceList;
10097         for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
10098           if ( !vol.IsFreeFace( iFace ))
10099             continue;
10100           // check if there is already a face with same nodes in a face set
10101           const SMDS_MeshElement* aFreeFace = 0;
10102           const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
10103           int nbNodes = vol.NbFaceNodes( iFace );
10104           set <const SMDS_MeshNode*> faceNodeSet;
10105           vol.GetFaceNodes( iFace, faceNodeSet );
10106           bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
10107           if ( isNewFace ) {
10108             // no such a face is given but it still can exist, check it
10109             vector<const SMDS_MeshNode *> nodes ( fNodes, fNodes + nbNodes);
10110             aFreeFace = aMesh->FindElement( nodes, SMDSAbs_Face, /*noMedium=*/false );
10111           }
10112           if ( !aFreeFace ) {
10113             // create a temporary face
10114             if ( nbNodes == 3 ) {
10115               //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
10116               aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2] );
10117             }
10118             else if ( nbNodes == 4 ) {
10119               //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
10120               aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
10121             }
10122             else {
10123               vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
10124               //aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
10125               aFreeFace = aMesh->AddPolygonalFace(poly_nodes);
10126             }
10127             if ( aFreeFace )
10128               tempFaceList.push_back( aFreeFace );
10129           }
10130
10131           if ( aFreeFace )
10132             freeFaceList.push_back( aFreeFace );
10133
10134         } // loop on faces of a volume
10135
10136         // choose one of several free faces of a volume
10137         // --------------------------------------------
10138         if ( freeFaceList.size() > 1 ) {
10139           // choose a face having max nb of nodes shared by other elems of a side
10140           int maxNbNodes = -1;
10141           list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
10142           while ( fIt != freeFaceList.end() ) { // loop on free faces
10143             int nbSharedNodes = 0;
10144             SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
10145             while ( nodeIt->more() ) { // loop on free face nodes
10146               const SMDS_MeshNode* n =
10147                 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
10148               SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
10149               while ( invElemIt->more() ) {
10150                 const SMDS_MeshElement* e = invElemIt->next();
10151                 nbSharedNodes += faceSet->count( e );
10152                 nbSharedNodes += elemSet->count( e );
10153               }
10154             }
10155             if ( nbSharedNodes > maxNbNodes ) {
10156               maxNbNodes = nbSharedNodes;
10157               freeFaceList.erase( freeFaceList.begin(), fIt++ );
10158             }
10159             else if ( nbSharedNodes == maxNbNodes ) {
10160               fIt++;
10161             }
10162             else {
10163               freeFaceList.erase( fIt++ ); // here fIt++ occurs before erase
10164             }
10165           }
10166           if ( freeFaceList.size() > 1 )
10167           {
10168             // could not choose one face, use another way
10169             // choose a face most close to the bary center of the opposite side
10170             gp_XYZ aBC( 0., 0., 0. );
10171             set <const SMDS_MeshNode*> addedNodes;
10172             TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
10173             eIt = elemSet2->begin();
10174             for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
10175               SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
10176               while ( nodeIt->more() ) { // loop on free face nodes
10177                 const SMDS_MeshNode* n =
10178                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
10179                 if ( addedNodes.insert( n ).second )
10180                   aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
10181               }
10182             }
10183             aBC /= addedNodes.size();
10184             double minDist = DBL_MAX;
10185             fIt = freeFaceList.begin();
10186             while ( fIt != freeFaceList.end() ) { // loop on free faces
10187               double dist = 0;
10188               SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
10189               while ( nodeIt->more() ) { // loop on free face nodes
10190                 const SMDS_MeshNode* n =
10191                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
10192                 gp_XYZ p( n->X(),n->Y(),n->Z() );
10193                 dist += ( aBC - p ).SquareModulus();
10194               }
10195               if ( dist < minDist ) {
10196                 minDist = dist;
10197                 freeFaceList.erase( freeFaceList.begin(), fIt++ );
10198               }
10199               else
10200                 fIt = freeFaceList.erase( fIt++ );
10201             }
10202           }
10203         } // choose one of several free faces of a volume
10204
10205         if ( freeFaceList.size() == 1 ) {
10206           const SMDS_MeshElement* aFreeFace = freeFaceList.front();
10207           faceSet->insert( aFreeFace );
10208           // complete a node set with nodes of a found free face
10209           //           for ( iNode = 0; iNode < ; iNode++ )
10210           //             nodeSet->insert( fNodes[ iNode ] );
10211         }
10212
10213       } // loop on volumes of a side
10214
10215       //       // complete a set of faces if new nodes in a nodeSet appeared
10216       //       // ----------------------------------------------------------
10217       //       if ( nodeSetSize != nodeSet->size() ) {
10218       //         for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
10219       //           SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
10220       //           while ( fIt->more() ) { // loop on faces sharing a node
10221       //             const SMDS_MeshElement* f = fIt->next();
10222       //             if ( faceSet->find( f ) == faceSet->end() ) {
10223       //               // check if all nodes are in nodeSet and
10224       //               // complete setOfFaceNodeSet if they are
10225       //               set <const SMDS_MeshNode*> faceNodeSet;
10226       //               SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
10227       //               bool allInSet = true;
10228       //               while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
10229       //                 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
10230       //                 if ( nodeSet->find( n ) == nodeSet->end() )
10231       //                   allInSet = false;
10232       //                 else
10233       //                   faceNodeSet.insert( n );
10234       //               }
10235       //               if ( allInSet ) {
10236       //                 faceSet->insert( f );
10237       //                 setOfFaceNodeSet.insert( faceNodeSet );
10238       //               }
10239       //             }
10240       //           }
10241       //         }
10242       //       }
10243     } // Create temporary faces, if there are volumes given
10244   } // loop on sides
10245
10246   if ( faceSet1.size() != faceSet2.size() ) {
10247     // delete temporary faces: they are in reverseElements of actual nodes
10248 //    SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
10249 //    while ( tmpFaceIt->more() )
10250 //      aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
10251 //    list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
10252 //    for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
10253 //      aMesh->RemoveElement(*tmpFaceIt);
10254     MESSAGE("Diff nb of faces");
10255     return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10256   }
10257
10258   // ============================================================
10259   // 2. Find nodes to merge:
10260   //              bind a node to remove to a node to put instead
10261   // ============================================================
10262
10263   TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
10264   if ( theFirstNode1 != theFirstNode2 )
10265     nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
10266   if ( theSecondNode1 != theSecondNode2 )
10267     nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
10268
10269   LinkID_Gen aLinkID_Gen( GetMeshDS() );
10270   set< long > linkIdSet; // links to process
10271   linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
10272
10273   typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
10274   list< NLink > linkList[2];
10275   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
10276   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
10277   // loop on links in linkList; find faces by links and append links
10278   // of the found faces to linkList
10279   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
10280   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ )
10281   {
10282     NLink link[] = { *linkIt[0], *linkIt[1] };
10283     long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
10284     if ( !linkIdSet.count( linkID ) )
10285       continue;
10286
10287     // by links, find faces in the face sets,
10288     // and find indices of link nodes in the found faces;
10289     // in a face set, there is only one or no face sharing a link
10290     // ---------------------------------------------------------------
10291
10292     const SMDS_MeshElement* face[] = { 0, 0 };
10293     vector<const SMDS_MeshNode*> fnodes[2];
10294     int iLinkNode[2][2];
10295     TIDSortedElemSet avoidSet;
10296     for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
10297       const SMDS_MeshNode* n1 = link[iSide].first;
10298       const SMDS_MeshNode* n2 = link[iSide].second;
10299       //cout << "Side " << iSide << " ";
10300       //cout << "L( " << n1->GetID() << ", " << n2->GetID() << " ) " << endl;
10301       // find a face by two link nodes
10302       face[ iSide ] = FindFaceInSet( n1, n2, *faceSetPtr[ iSide ], avoidSet,
10303                                      &iLinkNode[iSide][0], &iLinkNode[iSide][1] );
10304       if ( face[ iSide ])
10305       {
10306         //cout << " F " << face[ iSide]->GetID() <<endl;
10307         faceSetPtr[ iSide ]->erase( face[ iSide ]);
10308         // put face nodes to fnodes
10309         if ( face[ iSide ]->IsQuadratic() )
10310         {
10311           // use interlaced nodes iterator
10312           const SMDS_VtkFace* F = dynamic_cast<const SMDS_VtkFace*>( face[ iSide ]);
10313           if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
10314           SMDS_ElemIteratorPtr nIter = F->interlacedNodesElemIterator();
10315           while ( nIter->more() )
10316             fnodes[ iSide ].push_back( cast2Node( nIter->next() ));
10317         }
10318         else
10319         {
10320           fnodes[ iSide ].assign( face[ iSide ]->begin_nodes(),
10321                                   face[ iSide ]->end_nodes() );
10322         }
10323         fnodes[ iSide ].push_back( fnodes[ iSide ].front());
10324       }
10325     }
10326
10327     // check similarity of elements of the sides
10328     if (aResult == SEW_OK && (( face[0] && !face[1] ) || ( !face[0] && face[1] ))) {
10329       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
10330       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
10331         aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10332       }
10333       else {
10334         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10335       }
10336       break; // do not return because it's necessary to remove tmp faces
10337     }
10338
10339     // set nodes to merge
10340     // -------------------
10341
10342     if ( face[0] && face[1] )  {
10343       const int nbNodes = face[0]->NbNodes();
10344       if ( nbNodes != face[1]->NbNodes() ) {
10345         MESSAGE("Diff nb of face nodes");
10346         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10347         break; // do not return because it s necessary to remove tmp faces
10348       }
10349       bool reverse[] = { false, false }; // order of nodes in the link
10350       for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
10351         // analyse link orientation in faces
10352         int i1 = iLinkNode[ iSide ][ 0 ];
10353         int i2 = iLinkNode[ iSide ][ 1 ];
10354         reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
10355       }
10356       int di1 = reverse[0] ? -1 : +1, i1 = iLinkNode[0][1] + di1;
10357       int di2 = reverse[1] ? -1 : +1, i2 = iLinkNode[1][1] + di2;
10358       for ( int i = nbNodes - 2; i > 0; --i, i1 += di1, i2 += di2 )
10359       {
10360         nReplaceMap.insert  ( make_pair ( fnodes[0][ ( i1 + nbNodes ) % nbNodes ],
10361                                           fnodes[1][ ( i2 + nbNodes ) % nbNodes ]));
10362       }
10363
10364       // add other links of the faces to linkList
10365       // -----------------------------------------
10366
10367       for ( iNode = 0; iNode < nbNodes; iNode++ )  {
10368         linkID = aLinkID_Gen.GetLinkID( fnodes[0][iNode], fnodes[0][iNode+1] );
10369         pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
10370         if ( !iter_isnew.second ) { // already in a set: no need to process
10371           linkIdSet.erase( iter_isnew.first );
10372         }
10373         else // new in set == encountered for the first time: add
10374         {
10375           const SMDS_MeshNode* n1 = fnodes[0][ iNode ];
10376           const SMDS_MeshNode* n2 = fnodes[0][ iNode + 1];
10377           linkList[0].push_back ( NLink( n1, n2 ));
10378           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
10379         }
10380       }
10381     } // 2 faces found
10382
10383     if ( faceSetPtr[0]->empty() || faceSetPtr[1]->empty() )
10384       break;
10385
10386   } // loop on link lists
10387
10388   if ( aResult == SEW_OK &&
10389        ( //linkIt[0] != linkList[0].end() ||
10390          !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
10391     MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
10392              " " << (faceSetPtr[1]->empty()));
10393     aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10394   }
10395
10396   // ====================================================================
10397   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
10398   // ====================================================================
10399
10400   // delete temporary faces
10401 //  SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
10402 //  while ( tmpFaceIt->more() )
10403 //    aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
10404   list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
10405   for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
10406     aMesh->RemoveElement(*tmpFaceIt);
10407
10408   if ( aResult != SEW_OK)
10409     return aResult;
10410
10411   list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
10412   // loop on nodes replacement map
10413   TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
10414   for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
10415     if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
10416       const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
10417       nodeIDsToRemove.push_back( nToRemove->GetID() );
10418       // loop on elements sharing nToRemove
10419       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
10420       while ( invElemIt->more() ) {
10421         const SMDS_MeshElement* e = invElemIt->next();
10422         // get a new suite of nodes: make replacement
10423         int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
10424         vector< const SMDS_MeshNode*> nodes( nbNodes );
10425         SMDS_ElemIteratorPtr nIt = e->nodesIterator();
10426         while ( nIt->more() ) {
10427           const SMDS_MeshNode* n =
10428             static_cast<const SMDS_MeshNode*>( nIt->next() );
10429           nnIt = nReplaceMap.find( n );
10430           if ( nnIt != nReplaceMap.end() ) {
10431             nbReplaced++;
10432             n = (*nnIt).second;
10433           }
10434           nodes[ i++ ] = n;
10435         }
10436         //       if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
10437         //         elemIDsToRemove.push_back( e->GetID() );
10438         //       else
10439         if ( nbReplaced )
10440           {
10441             SMDSAbs_ElementType etyp = e->GetType();
10442             SMDS_MeshElement* newElem = this->AddElement(nodes, etyp, false);
10443             if (newElem)
10444               {
10445                 myLastCreatedElems.Append(newElem);
10446                 AddToSameGroups(newElem, e, aMesh);
10447                 int aShapeId = e->getshapeId();
10448                 if ( aShapeId )
10449                   {
10450                     aMesh->SetMeshElementOnShape( newElem, aShapeId );
10451                   }
10452               }
10453             aMesh->RemoveElement(e);
10454           }
10455       }
10456     }
10457
10458   Remove( nodeIDsToRemove, true );
10459
10460   return aResult;
10461 }
10462
10463 //================================================================================
10464 /*!
10465  * \brief Find corresponding nodes in two sets of faces
10466  * \param theSide1 - first face set
10467  * \param theSide2 - second first face
10468  * \param theFirstNode1 - a boundary node of set 1
10469  * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
10470  * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
10471  * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
10472  * \param nReplaceMap - output map of corresponding nodes
10473  * \return bool  - is a success or not
10474  */
10475 //================================================================================
10476
10477 #ifdef _DEBUG_
10478 //#define DEBUG_MATCHING_NODES
10479 #endif
10480
10481 SMESH_MeshEditor::Sew_Error
10482 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
10483                                     set<const SMDS_MeshElement*>& theSide2,
10484                                     const SMDS_MeshNode*          theFirstNode1,
10485                                     const SMDS_MeshNode*          theFirstNode2,
10486                                     const SMDS_MeshNode*          theSecondNode1,
10487                                     const SMDS_MeshNode*          theSecondNode2,
10488                                     TNodeNodeMap &                nReplaceMap)
10489 {
10490   set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
10491
10492   nReplaceMap.clear();
10493   if ( theFirstNode1 != theFirstNode2 )
10494     nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
10495   if ( theSecondNode1 != theSecondNode2 )
10496     nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
10497
10498   set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
10499   linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
10500
10501   list< NLink > linkList[2];
10502   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
10503   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
10504
10505   // loop on links in linkList; find faces by links and append links
10506   // of the found faces to linkList
10507   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
10508   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
10509     NLink link[] = { *linkIt[0], *linkIt[1] };
10510     if ( linkSet.find( link[0] ) == linkSet.end() )
10511       continue;
10512
10513     // by links, find faces in the face sets,
10514     // and find indices of link nodes in the found faces;
10515     // in a face set, there is only one or no face sharing a link
10516     // ---------------------------------------------------------------
10517
10518     const SMDS_MeshElement* face[] = { 0, 0 };
10519     list<const SMDS_MeshNode*> notLinkNodes[2];
10520     //bool reverse[] = { false, false }; // order of notLinkNodes
10521     int nbNodes[2];
10522     for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
10523     {
10524       const SMDS_MeshNode* n1 = link[iSide].first;
10525       const SMDS_MeshNode* n2 = link[iSide].second;
10526       set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
10527       set< const SMDS_MeshElement* > facesOfNode1;
10528       for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
10529       {
10530         // during a loop of the first node, we find all faces around n1,
10531         // during a loop of the second node, we find one face sharing both n1 and n2
10532         const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
10533         SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
10534         while ( fIt->more() ) { // loop on faces sharing a node
10535           const SMDS_MeshElement* f = fIt->next();
10536           if (faceSet->find( f ) != faceSet->end() && // f is in face set
10537               ! facesOfNode1.insert( f ).second ) // f encounters twice
10538           {
10539             if ( face[ iSide ] ) {
10540               MESSAGE( "2 faces per link " );
10541               return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10542             }
10543             face[ iSide ] = f;
10544             faceSet->erase( f );
10545
10546             // get not link nodes
10547             int nbN = f->NbNodes();
10548             if ( f->IsQuadratic() )
10549               nbN /= 2;
10550             nbNodes[ iSide ] = nbN;
10551             list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
10552             int i1 = f->GetNodeIndex( n1 );
10553             int i2 = f->GetNodeIndex( n2 );
10554             int iEnd = nbN, iBeg = -1, iDelta = 1;
10555             bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
10556             if ( reverse ) {
10557               std::swap( iEnd, iBeg ); iDelta = -1;
10558             }
10559             int i = i2;
10560             while ( true ) {
10561               i += iDelta;
10562               if ( i == iEnd ) i = iBeg + iDelta;
10563               if ( i == i1 ) break;
10564               nodes.push_back ( f->GetNode( i ) );
10565             }
10566           }
10567         }
10568       }
10569     }
10570     // check similarity of elements of the sides
10571     if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
10572       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
10573       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
10574         return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10575       }
10576       else {
10577         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10578       }
10579     }
10580
10581     // set nodes to merge
10582     // -------------------
10583
10584     if ( face[0] && face[1] )  {
10585       if ( nbNodes[0] != nbNodes[1] ) {
10586         MESSAGE("Diff nb of face nodes");
10587         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10588       }
10589 #ifdef DEBUG_MATCHING_NODES
10590       MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
10591                 << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
10592                 << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
10593 #endif
10594       int nbN = nbNodes[0];
10595       {
10596         list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
10597         list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
10598         for ( int i = 0 ; i < nbN - 2; ++i ) {
10599 #ifdef DEBUG_MATCHING_NODES
10600           MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
10601 #endif
10602           nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
10603         }
10604       }
10605
10606       // add other links of the face 1 to linkList
10607       // -----------------------------------------
10608
10609       const SMDS_MeshElement* f0 = face[0];
10610       const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
10611       for ( int i = 0; i < nbN; i++ )
10612       {
10613         const SMDS_MeshNode* n2 = f0->GetNode( i );
10614         pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
10615           linkSet.insert( SMESH_TLink( n1, n2 ));
10616         if ( !iter_isnew.second ) { // already in a set: no need to process
10617           linkSet.erase( iter_isnew.first );
10618         }
10619         else // new in set == encountered for the first time: add
10620         {
10621 #ifdef DEBUG_MATCHING_NODES
10622           MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
10623                     << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
10624 #endif
10625           linkList[0].push_back ( NLink( n1, n2 ));
10626           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
10627         }
10628         n1 = n2;
10629       }
10630     } // 2 faces found
10631   } // loop on link lists
10632
10633   return SEW_OK;
10634 }
10635
10636 //================================================================================
10637 /*!
10638   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10639   \param theElems - the list of elements (edges or faces) to be replicated
10640   The nodes for duplication could be found from these elements
10641   \param theNodesNot - list of nodes to NOT replicate
10642   \param theAffectedElems - the list of elements (cells and edges) to which the
10643   replicated nodes should be associated to.
10644   \return TRUE if operation has been completed successfully, FALSE otherwise
10645 */
10646 //================================================================================
10647
10648 bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
10649                                     const TIDSortedElemSet& theNodesNot,
10650                                     const TIDSortedElemSet& theAffectedElems )
10651 {
10652   myLastCreatedElems.Clear();
10653   myLastCreatedNodes.Clear();
10654
10655   if ( theElems.size() == 0 )
10656     return false;
10657
10658   SMESHDS_Mesh* aMeshDS = GetMeshDS();
10659   if ( !aMeshDS )
10660     return false;
10661
10662   bool res = false;
10663   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10664   // duplicate elements and nodes
10665   res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true );
10666   // replce nodes by duplications
10667   res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false );
10668   return res;
10669 }
10670
10671 //================================================================================
10672 /*!
10673   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10674   \param theMeshDS - mesh instance
10675   \param theElems - the elements replicated or modified (nodes should be changed)
10676   \param theNodesNot - nodes to NOT replicate
10677   \param theNodeNodeMap - relation of old node to new created node
10678   \param theIsDoubleElem - flag os to replicate element or modify
10679   \return TRUE if operation has been completed successfully, FALSE otherwise
10680 */
10681 //================================================================================
10682
10683 bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh*     theMeshDS,
10684                                     const TIDSortedElemSet& theElems,
10685                                     const TIDSortedElemSet& theNodesNot,
10686                                     std::map< const SMDS_MeshNode*,
10687                                     const SMDS_MeshNode* >& theNodeNodeMap,
10688                                     const bool theIsDoubleElem )
10689 {
10690   MESSAGE("doubleNodes");
10691   // iterate on through element and duplicate them (by nodes duplication)
10692   bool res = false;
10693   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10694   for ( ;  elemItr != theElems.end(); ++elemItr )
10695   {
10696     const SMDS_MeshElement* anElem = *elemItr;
10697     if (!anElem)
10698       continue;
10699
10700     bool isDuplicate = false;
10701     // duplicate nodes to duplicate element
10702     std::vector<const SMDS_MeshNode*> newNodes( anElem->NbNodes() );
10703     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10704     int ind = 0;
10705     while ( anIter->more() )
10706     {
10707
10708       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10709       SMDS_MeshNode* aNewNode = aCurrNode;
10710       if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() )
10711         aNewNode = (SMDS_MeshNode*)theNodeNodeMap[ aCurrNode ];
10712       else if ( theIsDoubleElem && theNodesNot.find( aCurrNode ) == theNodesNot.end() )
10713       {
10714         // duplicate node
10715         aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
10716         theNodeNodeMap[ aCurrNode ] = aNewNode;
10717         myLastCreatedNodes.Append( aNewNode );
10718       }
10719       isDuplicate |= (aCurrNode != aNewNode);
10720       newNodes[ ind++ ] = aNewNode;
10721     }
10722     if ( !isDuplicate )
10723       continue;
10724
10725     if ( theIsDoubleElem )
10726       AddElement(newNodes, anElem->GetType(), anElem->IsPoly());
10727     else
10728       {
10729       MESSAGE("ChangeElementNodes");
10730       theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
10731       }
10732     res = true;
10733   }
10734   return res;
10735 }
10736
10737 //================================================================================
10738 /*!
10739   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10740   \param theNodes - identifiers of nodes to be doubled
10741   \param theModifiedElems - identifiers of elements to be updated by the new (doubled)
10742          nodes. If list of element identifiers is empty then nodes are doubled but
10743          they not assigned to elements
10744   \return TRUE if operation has been completed successfully, FALSE otherwise
10745 */
10746 //================================================================================
10747
10748 bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes,
10749                                     const std::list< int >& theListOfModifiedElems )
10750 {
10751   MESSAGE("DoubleNodes");
10752   myLastCreatedElems.Clear();
10753   myLastCreatedNodes.Clear();
10754
10755   if ( theListOfNodes.size() == 0 )
10756     return false;
10757
10758   SMESHDS_Mesh* aMeshDS = GetMeshDS();
10759   if ( !aMeshDS )
10760     return false;
10761
10762   // iterate through nodes and duplicate them
10763
10764   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10765
10766   std::list< int >::const_iterator aNodeIter;
10767   for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
10768   {
10769     int aCurr = *aNodeIter;
10770     SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
10771     if ( !aNode )
10772       continue;
10773
10774     // duplicate node
10775
10776     const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
10777     if ( aNewNode )
10778     {
10779       anOldNodeToNewNode[ aNode ] = aNewNode;
10780       myLastCreatedNodes.Append( aNewNode );
10781     }
10782   }
10783
10784   // Create map of new nodes for modified elements
10785
10786   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
10787
10788   std::list< int >::const_iterator anElemIter;
10789   for ( anElemIter = theListOfModifiedElems.begin();
10790         anElemIter != theListOfModifiedElems.end(); ++anElemIter )
10791   {
10792     int aCurr = *anElemIter;
10793     SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
10794     if ( !anElem )
10795       continue;
10796
10797     vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
10798
10799     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10800     int ind = 0;
10801     while ( anIter->more() )
10802     {
10803       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10804       if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
10805       {
10806         const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
10807         aNodeArr[ ind++ ] = aNewNode;
10808       }
10809       else
10810         aNodeArr[ ind++ ] = aCurrNode;
10811     }
10812     anElemToNodes[ anElem ] = aNodeArr;
10813   }
10814
10815   // Change nodes of elements
10816
10817   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
10818     anElemToNodesIter = anElemToNodes.begin();
10819   for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
10820   {
10821     const SMDS_MeshElement* anElem = anElemToNodesIter->first;
10822     vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
10823     if ( anElem )
10824       {
10825       MESSAGE("ChangeElementNodes");
10826       aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
10827       }
10828   }
10829
10830   return true;
10831 }
10832
10833 namespace {
10834
10835   //================================================================================
10836   /*!
10837   \brief Check if element located inside shape
10838   \return TRUE if IN or ON shape, FALSE otherwise
10839   */
10840   //================================================================================
10841
10842   template<class Classifier>
10843   bool isInside(const SMDS_MeshElement* theElem,
10844                 Classifier&             theClassifier,
10845                 const double            theTol)
10846   {
10847     gp_XYZ centerXYZ (0, 0, 0);
10848     SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
10849     while (aNodeItr->more())
10850       centerXYZ += SMESH_TNodeXYZ(cast2Node( aNodeItr->next()));
10851
10852     gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
10853     theClassifier.Perform(aPnt, theTol);
10854     TopAbs_State aState = theClassifier.State();
10855     return (aState == TopAbs_IN || aState == TopAbs_ON );
10856   }
10857
10858   //================================================================================
10859   /*!
10860    * \brief Classifier of the 3D point on the TopoDS_Face
10861    *        with interaface suitable for isInside()
10862    */
10863   //================================================================================
10864
10865   struct _FaceClassifier
10866   {
10867     Extrema_ExtPS       _extremum;
10868     BRepAdaptor_Surface _surface;
10869     TopAbs_State        _state;
10870
10871     _FaceClassifier(const TopoDS_Face& face):_extremum(),_surface(face),_state(TopAbs_OUT)
10872     {
10873       _extremum.Initialize( _surface,
10874                             _surface.FirstUParameter(), _surface.LastUParameter(),
10875                             _surface.FirstVParameter(), _surface.LastVParameter(),
10876                             _surface.Tolerance(), _surface.Tolerance() );
10877     }
10878     void Perform(const gp_Pnt& aPnt, double theTol)
10879     {
10880       _state = TopAbs_OUT;
10881       _extremum.Perform(aPnt);
10882       if ( _extremum.IsDone() )
10883         for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol)
10884 #if OCC_VERSION_LARGE > 0x06040000 // Porting to OCCT6.5.1
10885           _state = ( _extremum.SquareDistance(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
10886 #else
10887           _state = ( _extremum.Value(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
10888 #endif
10889     }
10890     TopAbs_State State() const
10891     {
10892       return _state;
10893     }
10894   };
10895 }
10896
10897 //================================================================================
10898 /*!
10899   \brief Identify the elements that will be affected by node duplication (actual duplication is not performed.
10900   This method is the first step of DoubleNodeElemGroupsInRegion.
10901   \param theElems - list of groups of elements (edges or faces) to be replicated
10902   \param theNodesNot - list of groups of nodes not to replicated
10903   \param theShape - shape to detect affected elements (element which geometric center
10904          located on or inside shape).
10905          The replicated nodes should be associated to affected elements.
10906   \return groups of affected elements
10907   \sa DoubleNodeElemGroupsInRegion()
10908  */
10909 //================================================================================
10910
10911 bool SMESH_MeshEditor::AffectedElemGroupsInRegion( const TIDSortedElemSet& theElems,
10912                                                    const TIDSortedElemSet& theNodesNot,
10913                                                    const TopoDS_Shape&     theShape,
10914                                                    TIDSortedElemSet&       theAffectedElems)
10915 {
10916   if ( theShape.IsNull() )
10917     return false;
10918
10919   const double aTol = Precision::Confusion();
10920   auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
10921   auto_ptr<_FaceClassifier>              aFaceClassifier;
10922   if ( theShape.ShapeType() == TopAbs_SOLID )
10923   {
10924     bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
10925     bsc3d->PerformInfinitePoint(aTol);
10926   }
10927   else if (theShape.ShapeType() == TopAbs_FACE )
10928   {
10929     aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
10930   }
10931
10932   // iterates on indicated elements and get elements by back references from their nodes
10933   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10934   for ( ;  elemItr != theElems.end(); ++elemItr )
10935   {
10936     SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
10937     if (!anElem)
10938       continue;
10939
10940     SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
10941     while ( nodeItr->more() )
10942     {
10943       const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
10944       if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
10945         continue;
10946       SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
10947       while ( backElemItr->more() )
10948       {
10949         const SMDS_MeshElement* curElem = backElemItr->next();
10950         if ( curElem && theElems.find(curElem) == theElems.end() &&
10951              ( bsc3d.get() ?
10952                isInside( curElem, *bsc3d, aTol ) :
10953                isInside( curElem, *aFaceClassifier, aTol )))
10954           theAffectedElems.insert( curElem );
10955       }
10956     }
10957   }
10958   return true;
10959 }
10960
10961 //================================================================================
10962 /*!
10963   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10964   \param theElems - group of of elements (edges or faces) to be replicated
10965   \param theNodesNot - group of nodes not to replicate
10966   \param theShape - shape to detect affected elements (element which geometric center
10967   located on or inside shape).
10968   The replicated nodes should be associated to affected elements.
10969   \return TRUE if operation has been completed successfully, FALSE otherwise
10970 */
10971 //================================================================================
10972
10973 bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
10974                                             const TIDSortedElemSet& theNodesNot,
10975                                             const TopoDS_Shape&     theShape )
10976 {
10977   if ( theShape.IsNull() )
10978     return false;
10979
10980   const double aTol = Precision::Confusion();
10981   auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
10982   auto_ptr<_FaceClassifier>              aFaceClassifier;
10983   if ( theShape.ShapeType() == TopAbs_SOLID )
10984   {
10985     bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
10986     bsc3d->PerformInfinitePoint(aTol);
10987   }
10988   else if (theShape.ShapeType() == TopAbs_FACE )
10989   {
10990     aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
10991   }
10992
10993   // iterates on indicated elements and get elements by back references from their nodes
10994   TIDSortedElemSet anAffected;
10995   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10996   for ( ;  elemItr != theElems.end(); ++elemItr )
10997   {
10998     SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
10999     if (!anElem)
11000       continue;
11001
11002     SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
11003     while ( nodeItr->more() )
11004     {
11005       const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
11006       if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
11007         continue;
11008       SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
11009       while ( backElemItr->more() )
11010       {
11011         const SMDS_MeshElement* curElem = backElemItr->next();
11012         if ( curElem && theElems.find(curElem) == theElems.end() &&
11013              ( bsc3d.get() ?
11014                isInside( curElem, *bsc3d, aTol ) :
11015                isInside( curElem, *aFaceClassifier, aTol )))
11016           anAffected.insert( curElem );
11017       }
11018     }
11019   }
11020   return DoubleNodes( theElems, theNodesNot, anAffected );
11021 }
11022
11023 /*!
11024  *  \brief compute an oriented angle between two planes defined by four points.
11025  *  The vector (p0,p1) defines the intersection of the 2 planes (p0,p1,g1) and (p0,p1,g2)
11026  *  @param p0 base of the rotation axe
11027  *  @param p1 extremity of the rotation axe
11028  *  @param g1 belongs to the first plane
11029  *  @param g2 belongs to the second plane
11030  */
11031 double SMESH_MeshEditor::OrientedAngle(const gp_Pnt& p0, const gp_Pnt& p1, const gp_Pnt& g1, const gp_Pnt& g2)
11032 {
11033 //  MESSAGE("    p0: " << p0.X() << " " << p0.Y() << " " << p0.Z());
11034 //  MESSAGE("    p1: " << p1.X() << " " << p1.Y() << " " << p1.Z());
11035 //  MESSAGE("    g1: " << g1.X() << " " << g1.Y() << " " << g1.Z());
11036 //  MESSAGE("    g2: " << g2.X() << " " << g2.Y() << " " << g2.Z());
11037   gp_Vec vref(p0, p1);
11038   gp_Vec v1(p0, g1);
11039   gp_Vec v2(p0, g2);
11040   gp_Vec n1 = vref.Crossed(v1);
11041   gp_Vec n2 = vref.Crossed(v2);
11042   return n2.AngleWithRef(n1, vref);
11043 }
11044
11045 /*!
11046  * \brief Double nodes on shared faces between groups of volumes and create flat elements on demand.
11047  * The list of groups must describe a partition of the mesh volumes.
11048  * The nodes of the internal faces at the boundaries of the groups are doubled.
11049  * In option, the internal faces are replaced by flat elements.
11050  * Triangles are transformed in prisms, and quadrangles in hexahedrons.
11051  * The flat elements are stored in groups of volumes.
11052  * @param theElems - list of groups of volumes, where a group of volume is a set of
11053  * SMDS_MeshElements sorted by Id.
11054  * @param createJointElems - if TRUE, create the elements
11055  * @return TRUE if operation has been completed successfully, FALSE otherwise
11056  */
11057 bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSortedElemSet>& theElems,
11058                                                      bool createJointElems)
11059 {
11060   MESSAGE("----------------------------------------------");
11061   MESSAGE("SMESH_MeshEditor::doubleNodesOnGroupBoundaries");
11062   MESSAGE("----------------------------------------------");
11063
11064   SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
11065   meshDS->BuildDownWardConnectivity(true);
11066   CHRONO(50);
11067   SMDS_UnstructuredGrid *grid = meshDS->getGrid();
11068
11069   // --- build the list of faces shared by 2 domains (group of elements), with their domain and volume indexes
11070   //     build the list of cells with only a node or an edge on the border, with their domain and volume indexes
11071   //     build the list of nodes shared by 2 or more domains, with their domain indexes
11072
11073   std::map<DownIdType, std::map<int,int>, DownIdCompare> faceDomains; // face --> (id domain --> id volume)
11074   std::map<int,int>celldom; // cell vtkId --> domain
11075   std::map<DownIdType, std::map<int,int>, DownIdCompare> cellDomains;  // oldNode --> (id domain --> id cell)
11076   std::map<int, std::map<int,int> > nodeDomains; // oldId -->  (domainId --> newId)
11077   faceDomains.clear();
11078   celldom.clear();
11079   cellDomains.clear();
11080   nodeDomains.clear();
11081   std::map<int,int> emptyMap;
11082   std::set<int> emptySet;
11083   emptyMap.clear();
11084
11085   for (int idom = 0; idom < theElems.size(); idom++)
11086     {
11087
11088       // --- build a map (face to duplicate --> volume to modify)
11089       //     with all the faces shared by 2 domains (group of elements)
11090       //     and corresponding volume of this domain, for each shared face.
11091       //     a volume has a face shared by 2 domains if it has a neighbor which is not in his domain.
11092
11093       //MESSAGE("Domain " << idom);
11094       const TIDSortedElemSet& domain = theElems[idom];
11095       TIDSortedElemSet::const_iterator elemItr = domain.begin();
11096       for (; elemItr != domain.end(); ++elemItr)
11097         {
11098           SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
11099           if (!anElem)
11100             continue;
11101           int vtkId = anElem->getVtkId();
11102           //MESSAGE("  vtkId " << vtkId << " smdsId " << anElem->GetID());
11103           int neighborsVtkIds[NBMAXNEIGHBORS];
11104           int downIds[NBMAXNEIGHBORS];
11105           unsigned char downTypes[NBMAXNEIGHBORS];
11106           int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
11107           for (int n = 0; n < nbNeighbors; n++)
11108             {
11109               int smdsId = meshDS->fromVtkToSmds(neighborsVtkIds[n]);
11110               const SMDS_MeshElement* elem = meshDS->FindElement(smdsId);
11111               if (! domain.count(elem)) // neighbor is in another domain : face is shared
11112                 {
11113                   DownIdType face(downIds[n], downTypes[n]);
11114                   if (!faceDomains.count(face))
11115                     faceDomains[face] = emptyMap; // create an empty entry for face
11116                   if (!faceDomains[face].count(idom))
11117                     {
11118                       faceDomains[face][idom] = vtkId; // volume associated to face in this domain
11119                       celldom[vtkId] = idom;
11120                       //MESSAGE("       cell with a border " << vtkId << " domain " << idom);
11121                     }
11122                 }
11123             }
11124         }
11125     }
11126
11127   //MESSAGE("Number of shared faces " << faceDomains.size());
11128   std::map<DownIdType, std::map<int, int>, DownIdCompare>::iterator itface;
11129
11130   // --- explore the shared faces domain by domain,
11131   //     explore the nodes of the face and see if they belong to a cell in the domain,
11132   //     which has only a node or an edge on the border (not a shared face)
11133
11134   for (int idomain = 0; idomain < theElems.size(); idomain++)
11135     {
11136       //MESSAGE("Domain " << idomain);
11137       const TIDSortedElemSet& domain = theElems[idomain];
11138       itface = faceDomains.begin();
11139       for (; itface != faceDomains.end(); ++itface)
11140         {
11141           std::map<int, int> domvol = itface->second;
11142           if (!domvol.count(idomain))
11143             continue;
11144           DownIdType face = itface->first;
11145           //MESSAGE(" --- face " << face.cellId);
11146           std::set<int> oldNodes;
11147           oldNodes.clear();
11148           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11149           std::set<int>::iterator itn = oldNodes.begin();
11150           for (; itn != oldNodes.end(); ++itn)
11151             {
11152               int oldId = *itn;
11153               //MESSAGE("     node " << oldId);
11154               vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId);
11155               for (int i=0; i<l.ncells; i++)
11156                 {
11157                   int vtkId = l.cells[i];
11158                   const SMDS_MeshElement* anElem = GetMeshDS()->FindElement(GetMeshDS()->fromVtkToSmds(vtkId));
11159                   if (!domain.count(anElem))
11160                     continue;
11161                   int vtkType = grid->GetCellType(vtkId);
11162                   int downId = grid->CellIdToDownId(vtkId);
11163                   if (downId < 0)
11164                     {
11165                       MESSAGE("doubleNodesOnGroupBoundaries: internal algorithm problem");
11166                       continue; // not OK at this stage of the algorithm:
11167                                 //no cells created after BuildDownWardConnectivity
11168                     }
11169                   DownIdType aCell(downId, vtkType);
11170                   if (!cellDomains.count(aCell))
11171                     cellDomains[aCell] = emptyMap; // create an empty entry for cell
11172                   cellDomains[aCell][idomain] = vtkId;
11173                   celldom[vtkId] = idomain;
11174                   //MESSAGE("       cell " << vtkId << " domain " << idomain);
11175                 }
11176             }
11177         }
11178     }
11179
11180   // --- explore the shared faces domain by domain, to duplicate the nodes in a coherent way
11181   //     for each shared face, get the nodes
11182   //     for each node, for each domain of the face, create a clone of the node
11183
11184   // --- edges at the intersection of 3 or 4 domains, with the order of domains to build
11185   //     junction elements of type prism or hexa. the key is the pair of nodesId (lower first)
11186   //     the value is the ordered domain ids. (more than 4 domains not taken into account)
11187
11188   std::map<std::vector<int>, std::vector<int> > edgesMultiDomains; // nodes of edge --> ordered domains
11189   std::map<int, std::vector<int> > mutipleNodes; // nodes multi domains with domain order
11190   std::map<int, std::vector<int> > mutipleNodesToFace; // nodes multi domains with domain order to transform in Face (junction between 3 or more 2D domains)
11191
11192   for (int idomain = 0; idomain < theElems.size(); idomain++)
11193     {
11194       itface = faceDomains.begin();
11195       for (; itface != faceDomains.end(); ++itface)
11196         {
11197           std::map<int, int> domvol = itface->second;
11198           if (!domvol.count(idomain))
11199             continue;
11200           DownIdType face = itface->first;
11201           //MESSAGE(" --- face " << face.cellId);
11202           std::set<int> oldNodes;
11203           oldNodes.clear();
11204           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11205           std::set<int>::iterator itn = oldNodes.begin();
11206           for (; itn != oldNodes.end(); ++itn)
11207             {
11208               int oldId = *itn;
11209               //MESSAGE("-+-+-a node " << oldId);
11210               if (!nodeDomains.count(oldId))
11211                 nodeDomains[oldId] = emptyMap; // create an empty entry for node
11212               if (nodeDomains[oldId].empty())
11213                 {
11214                   nodeDomains[oldId][idomain] = oldId; // keep the old node in the first domain
11215                   //MESSAGE("-+-+-b     oldNode " << oldId << " domain " << idomain);
11216                 }
11217               std::map<int, int>::iterator itdom = domvol.begin();
11218               for (; itdom != domvol.end(); ++itdom)
11219                 {
11220                   int idom = itdom->first;
11221                   //MESSAGE("         domain " << idom);
11222                   if (!nodeDomains[oldId].count(idom)) // --- node to clone
11223                     {
11224                       if (nodeDomains[oldId].size() >= 2) // a multiple node
11225                         {
11226                           vector<int> orderedDoms;
11227                           //MESSAGE("multiple node " << oldId);
11228                           if (mutipleNodes.count(oldId))
11229                             orderedDoms = mutipleNodes[oldId];
11230                           else
11231                             {
11232                               map<int,int>::iterator it = nodeDomains[oldId].begin();
11233                               for (; it != nodeDomains[oldId].end(); ++it)
11234                                 orderedDoms.push_back(it->first);
11235                             }
11236                           orderedDoms.push_back(idom); // TODO order ==> push_front or back
11237                           //stringstream txt;
11238                           //for (int i=0; i<orderedDoms.size(); i++)
11239                           //  txt << orderedDoms[i] << " ";
11240                           //MESSAGE("orderedDoms " << txt.str());
11241                           mutipleNodes[oldId] = orderedDoms;
11242                         }
11243                       double *coords = grid->GetPoint(oldId);
11244                       SMDS_MeshNode *newNode = meshDS->AddNode(coords[0], coords[1], coords[2]);
11245                       int newId = newNode->getVtkId();
11246                       nodeDomains[oldId][idom] = newId; // cloned node for other domains
11247                       //MESSAGE("-+-+-c     oldNode " << oldId << " domain " << idomain << " newNode " << newId << " domain " << idom << " size=" <<nodeDomains[oldId].size());
11248                     }
11249                 }
11250             }
11251         }
11252     }
11253
11254   for (int idomain = 0; idomain < theElems.size(); idomain++)
11255     {
11256       itface = faceDomains.begin();
11257       for (; itface != faceDomains.end(); ++itface)
11258         {
11259           std::map<int, int> domvol = itface->second;
11260           if (!domvol.count(idomain))
11261             continue;
11262           DownIdType face = itface->first;
11263           //MESSAGE(" --- face " << face.cellId);
11264           std::set<int> oldNodes;
11265           oldNodes.clear();
11266           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11267           int nbMultipleNodes = 0;
11268           std::set<int>::iterator itn = oldNodes.begin();
11269           for (; itn != oldNodes.end(); ++itn)
11270             {
11271               int oldId = *itn;
11272               if (mutipleNodes.count(oldId))
11273                 nbMultipleNodes++;
11274             }
11275           if (nbMultipleNodes > 1) // check if an edge of the face is shared between 3 or more domains
11276             {
11277               //MESSAGE("multiple Nodes detected on a shared face");
11278               int downId = itface->first.cellId;
11279               unsigned char cellType = itface->first.cellType;
11280               // --- shared edge or shared face ?
11281               if ((cellType == VTK_LINE) || (cellType == VTK_QUADRATIC_EDGE)) // shared edge (between two faces)
11282                 {
11283                   int nodes[3];
11284                   int nbNodes = grid->getDownArray(cellType)->getNodes(downId, nodes);
11285                   for (int i=0; i< nbNodes; i=i+nbNodes-1) // i=0 , i=nbNodes-1
11286                     if (mutipleNodes.count(nodes[i]))
11287                       if (!mutipleNodesToFace.count(nodes[i]))
11288                         mutipleNodesToFace[nodes[i]] = mutipleNodes[nodes[i]];
11289                 }
11290               else // shared face (between two volumes)
11291                 {
11292                   int nbEdges = grid->getDownArray(cellType)->getNumberOfDownCells(downId);
11293                   const int* downEdgeIds = grid->getDownArray(cellType)->getDownCells(downId);
11294                   const unsigned char* edgeType = grid->getDownArray(cellType)->getDownTypes(downId);
11295                   for (int ie =0; ie < nbEdges; ie++)
11296                     {
11297                       int nodes[3];
11298                       int nbNodes = grid->getDownArray(edgeType[ie])->getNodes(downEdgeIds[ie], nodes);
11299                       if (mutipleNodes.count(nodes[0]) && mutipleNodes.count(nodes[nbNodes-1]))
11300                         {
11301                           vector<int> vn0 = mutipleNodes[nodes[0]];
11302                           vector<int> vn1 = mutipleNodes[nodes[nbNodes - 1]];
11303                           vector<int> doms;
11304                           for (int i0 = 0; i0 < vn0.size(); i0++)
11305                             for (int i1 = 0; i1 < vn1.size(); i1++)
11306                               if (vn0[i0] == vn1[i1])
11307                                 doms.push_back(vn0[i0]);
11308                           if (doms.size() >2)
11309                             {
11310                               //MESSAGE(" detect edgesMultiDomains " << nodes[0] << " " << nodes[nbNodes - 1]);
11311                               double *coords = grid->GetPoint(nodes[0]);
11312                               gp_Pnt p0(coords[0], coords[1], coords[2]);
11313                               coords = grid->GetPoint(nodes[nbNodes - 1]);
11314                               gp_Pnt p1(coords[0], coords[1], coords[2]);
11315                               gp_Pnt gref;
11316                               int vtkVolIds[1000];  // an edge can belong to a lot of volumes
11317                               map<int, SMDS_VtkVolume*> domvol; // domain --> a volume with the edge
11318                               map<int, double> angleDom; // oriented angles between planes defined by edge and volume centers
11319                               int nbvol = grid->GetParentVolumes(vtkVolIds, downEdgeIds[ie], edgeType[ie]);
11320                               for (int id=0; id < doms.size(); id++)
11321                                 {
11322                                   int idom = doms[id];
11323                                   for (int ivol=0; ivol<nbvol; ivol++)
11324                                     {
11325                                       int smdsId = meshDS->fromVtkToSmds(vtkVolIds[ivol]);
11326                                       SMDS_MeshElement* elem = (SMDS_MeshElement*)meshDS->FindElement(smdsId);
11327                                       if (theElems[idom].count(elem))
11328                                         {
11329                                           SMDS_VtkVolume* svol = dynamic_cast<SMDS_VtkVolume*>(elem);
11330                                           domvol[idom] = svol;
11331                                           //MESSAGE("  domain " << idom << " volume " << elem->GetID());
11332                                           double values[3];
11333                                           vtkIdType npts = 0;
11334                                           vtkIdType* pts = 0;
11335                                           grid->GetCellPoints(vtkVolIds[ivol], npts, pts);
11336                                           SMDS_VtkVolume::gravityCenter(grid, pts, npts, values);
11337                                           if (id ==0)
11338                                             {
11339                                               gref.SetXYZ(gp_XYZ(values[0], values[1], values[2]));
11340                                               angleDom[idom] = 0;
11341                                             }
11342                                           else
11343                                             {
11344                                               gp_Pnt g(values[0], values[1], values[2]);
11345                                               angleDom[idom] = OrientedAngle(p0, p1, gref, g); // -pi<angle<+pi
11346                                               //MESSAGE("  angle=" << angleDom[idom]);
11347                                             }
11348                                           break;
11349                                         }
11350                                     }
11351                                 }
11352                               map<double, int> sortedDom; // sort domains by angle
11353                               for (map<int, double>::iterator ia = angleDom.begin(); ia != angleDom.end(); ++ia)
11354                                 sortedDom[ia->second] = ia->first;
11355                               vector<int> vnodes;
11356                               vector<int> vdom;
11357                               for (map<double, int>::iterator ib = sortedDom.begin(); ib != sortedDom.end(); ++ib)
11358                                 {
11359                                   vdom.push_back(ib->second);
11360                                   //MESSAGE("  ordered domain " << ib->second << "  angle " << ib->first);
11361                                 }
11362                               for (int ino = 0; ino < nbNodes; ino++)
11363                                 vnodes.push_back(nodes[ino]);
11364                               edgesMultiDomains[vnodes] = vdom; // nodes vector --> ordered domains
11365                             }
11366                         }
11367                     }
11368                 }
11369             }
11370         }
11371     }
11372
11373   // --- iterate on shared faces (volumes to modify, face to extrude)
11374   //     get node id's of the face (id SMDS = id VTK)
11375   //     create flat element with old and new nodes if requested
11376
11377   // --- new quad nodes on flat quad elements: oldId --> ((domain1 X domain2) --> newId)
11378   //     (domain1 X domain2) = domain1 + MAXINT*domain2
11379
11380   std::map<int, std::map<long,int> > nodeQuadDomains;
11381   std::map<std::string, SMESH_Group*> mapOfJunctionGroups;
11382
11383   if (createJointElems)
11384     {
11385       int idg;
11386       string joints2DName = "joints2D";
11387       mapOfJunctionGroups[joints2DName] = this->myMesh->AddGroup(SMDSAbs_Face, joints2DName.c_str(), idg);
11388       SMESHDS_Group *joints2DGrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[joints2DName]->GetGroupDS());
11389       string joints3DName = "joints3D";
11390       mapOfJunctionGroups[joints3DName] = this->myMesh->AddGroup(SMDSAbs_Volume, joints3DName.c_str(), idg);
11391       SMESHDS_Group *joints3DGrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[joints3DName]->GetGroupDS());
11392
11393       itface = faceDomains.begin();
11394       for (; itface != faceDomains.end(); ++itface)
11395         {
11396           DownIdType face = itface->first;
11397           std::set<int> oldNodes;
11398           std::set<int>::iterator itn;
11399           oldNodes.clear();
11400           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11401
11402           std::map<int, int> domvol = itface->second;
11403           std::map<int, int>::iterator itdom = domvol.begin();
11404           int dom1 = itdom->first;
11405           int vtkVolId = itdom->second;
11406           itdom++;
11407           int dom2 = itdom->first;
11408           SMDS_MeshCell *vol = grid->extrudeVolumeFromFace(vtkVolId, dom1, dom2, oldNodes, nodeDomains,
11409                                                              nodeQuadDomains);
11410           stringstream grpname;
11411           grpname << "j_";
11412           if (dom1 < dom2)
11413             grpname << dom1 << "_" << dom2;
11414           else
11415             grpname << dom2 << "_" << dom1;
11416           string namegrp = grpname.str();
11417           if (!mapOfJunctionGroups.count(namegrp))
11418             mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(vol->GetType(), namegrp.c_str(), idg);
11419           SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11420           if (sgrp)
11421             sgrp->Add(vol->GetID());
11422           if (vol->GetType() == SMDSAbs_Volume)
11423             joints3DGrp->Add(vol->GetID());
11424           else if (vol->GetType() == SMDSAbs_Face)
11425             joints2DGrp->Add(vol->GetID());
11426         }
11427     }
11428
11429   // --- create volumes on multiple domain intersection if requested
11430   //     iterate on mutipleNodesToFace
11431   //     iterate on edgesMultiDomains
11432
11433   if (createJointElems)
11434     {
11435       // --- iterate on mutipleNodesToFace
11436
11437       std::map<int, std::vector<int> >::iterator itn =  mutipleNodesToFace.begin();
11438       for (; itn != mutipleNodesToFace.end(); ++itn)
11439         {
11440           int node = itn->first;
11441           vector<int> orderDom = itn->second;
11442           vector<vtkIdType> orderedNodes;
11443           for (int idom = 0; idom <orderDom.size(); idom++)
11444             orderedNodes.push_back( nodeDomains[node][orderDom[idom]] );
11445             SMDS_MeshFace* face = this->GetMeshDS()->AddFaceFromVtkIds(orderedNodes);
11446
11447             stringstream grpname;
11448             grpname << "m2j_";
11449             grpname << 0 << "_" << 0;
11450             int idg;
11451             string namegrp = grpname.str();
11452             if (!mapOfJunctionGroups.count(namegrp))
11453               mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Face, namegrp.c_str(), idg);
11454             SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11455             if (sgrp)
11456               sgrp->Add(face->GetID());
11457         }
11458
11459       // --- iterate on edgesMultiDomains
11460
11461       std::map<std::vector<int>, std::vector<int> >::iterator ite = edgesMultiDomains.begin();
11462       for (; ite != edgesMultiDomains.end(); ++ite)
11463         {
11464           vector<int> nodes = ite->first;
11465           vector<int> orderDom = ite->second;
11466           vector<vtkIdType> orderedNodes;
11467           if (nodes.size() == 2)
11468             {
11469               //MESSAGE(" use edgesMultiDomains " << nodes[0] << " " << nodes[1]);
11470               for (int ino=0; ino < nodes.size(); ino++)
11471                 if (orderDom.size() == 3)
11472                   for (int idom = 0; idom <orderDom.size(); idom++)
11473                     orderedNodes.push_back( nodeDomains[nodes[ino]][orderDom[idom]] );
11474                 else
11475                   for (int idom = orderDom.size()-1; idom >=0; idom--)
11476                     orderedNodes.push_back( nodeDomains[nodes[ino]][orderDom[idom]] );
11477               SMDS_MeshVolume* vol = this->GetMeshDS()->AddVolumeFromVtkIds(orderedNodes);
11478
11479               int idg;
11480               string namegrp = "jointsMultiples";
11481               if (!mapOfJunctionGroups.count(namegrp))
11482                 mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
11483               SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11484               if (sgrp)
11485                 sgrp->Add(vol->GetID());
11486             }
11487           else
11488             {
11489               INFOS("Quadratic multiple joints not implemented");
11490               // TODO quadratic nodes
11491             }
11492         }
11493     }
11494
11495   // --- list the explicit faces and edges of the mesh that need to be modified,
11496   //     i.e. faces and edges built with one or more duplicated nodes.
11497   //     associate these faces or edges to their corresponding domain.
11498   //     only the first domain found is kept when a face or edge is shared
11499
11500   std::map<DownIdType, std::map<int,int>, DownIdCompare> faceOrEdgeDom; // cellToModify --> (id domain --> id cell)
11501   std::map<int,int> feDom; // vtk id of cell to modify --> id domain
11502   faceOrEdgeDom.clear();
11503   feDom.clear();
11504
11505   for (int idomain = 0; idomain < theElems.size(); idomain++)
11506     {
11507       std::map<int, std::map<int, int> >::const_iterator itnod = nodeDomains.begin();
11508       for (; itnod != nodeDomains.end(); ++itnod)
11509         {
11510           int oldId = itnod->first;
11511           //MESSAGE("     node " << oldId);
11512           vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId);
11513           for (int i = 0; i < l.ncells; i++)
11514             {
11515               int vtkId = l.cells[i];
11516               int vtkType = grid->GetCellType(vtkId);
11517               int downId = grid->CellIdToDownId(vtkId);
11518               if (downId < 0)
11519                 continue; // new cells: not to be modified
11520               DownIdType aCell(downId, vtkType);
11521               int volParents[1000];
11522               int nbvol = grid->GetParentVolumes(volParents, vtkId);
11523               for (int j = 0; j < nbvol; j++)
11524                 if (celldom.count(volParents[j]) && (celldom[volParents[j]] == idomain))
11525                   if (!feDom.count(vtkId))
11526                     {
11527                       feDom[vtkId] = idomain;
11528                       faceOrEdgeDom[aCell] = emptyMap;
11529                       faceOrEdgeDom[aCell][idomain] = vtkId; // affect face or edge to the first domain only
11530                       //MESSAGE("affect cell " << this->GetMeshDS()->fromVtkToSmds(vtkId) << " domain " << idomain
11531                       //        << " type " << vtkType << " downId " << downId);
11532                     }
11533             }
11534         }
11535     }
11536
11537   // --- iterate on shared faces (volumes to modify, face to extrude)
11538   //     get node id's of the face
11539   //     replace old nodes by new nodes in volumes, and update inverse connectivity
11540
11541   std::map<DownIdType, std::map<int,int>, DownIdCompare>* maps[3] = {&faceDomains, &cellDomains, &faceOrEdgeDom};
11542   for (int m=0; m<3; m++)
11543     {
11544       std::map<DownIdType, std::map<int,int>, DownIdCompare>* amap = maps[m];
11545       itface = (*amap).begin();
11546       for (; itface != (*amap).end(); ++itface)
11547         {
11548           DownIdType face = itface->first;
11549           std::set<int> oldNodes;
11550           std::set<int>::iterator itn;
11551           oldNodes.clear();
11552           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11553           //MESSAGE("examine cell, downId " << face.cellId << " type " << int(face.cellType));
11554           std::map<int, int> localClonedNodeIds;
11555
11556           std::map<int, int> domvol = itface->second;
11557           std::map<int, int>::iterator itdom = domvol.begin();
11558           for (; itdom != domvol.end(); ++itdom)
11559             {
11560               int idom = itdom->first;
11561               int vtkVolId = itdom->second;
11562               //MESSAGE("modify nodes of cell " << this->GetMeshDS()->fromVtkToSmds(vtkVolId) << " domain " << idom);
11563               localClonedNodeIds.clear();
11564               for (itn = oldNodes.begin(); itn != oldNodes.end(); ++itn)
11565                 {
11566                   int oldId = *itn;
11567                   if (nodeDomains[oldId].count(idom))
11568                     {
11569                       localClonedNodeIds[oldId] = nodeDomains[oldId][idom];
11570                       //MESSAGE("     node " << oldId << " --> " << localClonedNodeIds[oldId]);
11571                     }
11572                 }
11573               meshDS->ModifyCellNodes(vtkVolId, localClonedNodeIds);
11574             }
11575         }
11576     }
11577
11578   meshDS->CleanDownWardConnectivity(); // Mesh has been modified, downward connectivity is no more usable, free memory
11579   grid->BuildLinks();
11580
11581   CHRONOSTOP(50);
11582   counters::stats();
11583   return true;
11584 }
11585
11586 /*!
11587  * \brief Double nodes on some external faces and create flat elements.
11588  * Flat elements are mainly used by some types of mechanic calculations.
11589  *
11590  * Each group of the list must be constituted of faces.
11591  * Triangles are transformed in prisms, and quadrangles in hexahedrons.
11592  * @param theElems - list of groups of faces, where a group of faces is a set of
11593  * SMDS_MeshElements sorted by Id.
11594  * @return TRUE if operation has been completed successfully, FALSE otherwise
11595  */
11596 bool SMESH_MeshEditor::CreateFlatElementsOnFacesGroups(const std::vector<TIDSortedElemSet>& theElems)
11597 {
11598   MESSAGE("-------------------------------------------------");
11599   MESSAGE("SMESH_MeshEditor::CreateFlatElementsOnFacesGroups");
11600   MESSAGE("-------------------------------------------------");
11601
11602   SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
11603
11604   // --- For each group of faces
11605   //     duplicate the nodes, create a flat element based on the face
11606   //     replace the nodes of the faces by their clones
11607
11608   std::map<const SMDS_MeshNode*, const SMDS_MeshNode*> clonedNodes;
11609   std::map<const SMDS_MeshNode*, const SMDS_MeshNode*> intermediateNodes;
11610   clonedNodes.clear();
11611   intermediateNodes.clear();
11612   std::map<std::string, SMESH_Group*> mapOfJunctionGroups;
11613   mapOfJunctionGroups.clear();
11614
11615   for (int idom = 0; idom < theElems.size(); idom++)
11616     {
11617       const TIDSortedElemSet& domain = theElems[idom];
11618       TIDSortedElemSet::const_iterator elemItr = domain.begin();
11619       for (; elemItr != domain.end(); ++elemItr)
11620         {
11621           SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
11622           SMDS_MeshFace* aFace = dynamic_cast<SMDS_MeshFace*> (anElem);
11623           if (!aFace)
11624             continue;
11625           // MESSAGE("aFace=" << aFace->GetID());
11626           bool isQuad = aFace->IsQuadratic();
11627           vector<const SMDS_MeshNode*> ln0, ln1, ln2, ln3, ln4;
11628
11629           // --- clone the nodes, create intermediate nodes for non medium nodes of a quad face
11630
11631           SMDS_ElemIteratorPtr nodeIt = aFace->nodesIterator();
11632           while (nodeIt->more())
11633             {
11634               const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*> (nodeIt->next());
11635               bool isMedium = isQuad && (aFace->IsMediumNode(node));
11636               if (isMedium)
11637                 ln2.push_back(node);
11638               else
11639                 ln0.push_back(node);
11640
11641               const SMDS_MeshNode* clone = 0;
11642               if (!clonedNodes.count(node))
11643                 {
11644                   clone = meshDS->AddNode(node->X(), node->Y(), node->Z());
11645                   clonedNodes[node] = clone;
11646                 }
11647               else
11648                 clone = clonedNodes[node];
11649
11650               if (isMedium)
11651                 ln3.push_back(clone);
11652               else
11653                 ln1.push_back(clone);
11654
11655               const SMDS_MeshNode* inter = 0;
11656               if (isQuad && (!isMedium))
11657                 {
11658                   if (!intermediateNodes.count(node))
11659                     {
11660                       inter = meshDS->AddNode(node->X(), node->Y(), node->Z());
11661                       intermediateNodes[node] = inter;
11662                     }
11663                   else
11664                     inter = intermediateNodes[node];
11665                   ln4.push_back(inter);
11666                 }
11667             }
11668
11669           // --- extrude the face
11670
11671           vector<const SMDS_MeshNode*> ln;
11672           SMDS_MeshVolume* vol = 0;
11673           vtkIdType aType = aFace->GetVtkType();
11674           switch (aType)
11675           {
11676             case VTK_TRIANGLE:
11677               vol = meshDS->AddVolume(ln0[2], ln0[1], ln0[0], ln1[2], ln1[1], ln1[0]);
11678               // MESSAGE("vol prism " << vol->GetID());
11679               ln.push_back(ln1[0]);
11680               ln.push_back(ln1[1]);
11681               ln.push_back(ln1[2]);
11682               break;
11683             case VTK_QUAD:
11684               vol = meshDS->AddVolume(ln0[3], ln0[2], ln0[1], ln0[0], ln1[3], ln1[2], ln1[1], ln1[0]);
11685               // MESSAGE("vol hexa " << vol->GetID());
11686               ln.push_back(ln1[0]);
11687               ln.push_back(ln1[1]);
11688               ln.push_back(ln1[2]);
11689               ln.push_back(ln1[3]);
11690               break;
11691             case VTK_QUADRATIC_TRIANGLE:
11692               vol = meshDS->AddVolume(ln1[0], ln1[1], ln1[2], ln0[0], ln0[1], ln0[2], ln3[0], ln3[1], ln3[2],
11693                                       ln2[0], ln2[1], ln2[2], ln4[0], ln4[1], ln4[2]);
11694               // MESSAGE("vol quad prism " << vol->GetID());
11695               ln.push_back(ln1[0]);
11696               ln.push_back(ln1[1]);
11697               ln.push_back(ln1[2]);
11698               ln.push_back(ln3[0]);
11699               ln.push_back(ln3[1]);
11700               ln.push_back(ln3[2]);
11701               break;
11702             case VTK_QUADRATIC_QUAD:
11703 //              vol = meshDS->AddVolume(ln0[0], ln0[1], ln0[2], ln0[3], ln1[0], ln1[1], ln1[2], ln1[3],
11704 //                                      ln2[0], ln2[1], ln2[2], ln2[3], ln3[0], ln3[1], ln3[2], ln3[3],
11705 //                                      ln4[0], ln4[1], ln4[2], ln4[3]);
11706               vol = meshDS->AddVolume(ln1[0], ln1[1], ln1[2], ln1[3], ln0[0], ln0[1], ln0[2], ln0[3],
11707                                       ln3[0], ln3[1], ln3[2], ln3[3], ln2[0], ln2[1], ln2[2], ln2[3],
11708                                       ln4[0], ln4[1], ln4[2], ln4[3]);
11709               // MESSAGE("vol quad hexa " << vol->GetID());
11710               ln.push_back(ln1[0]);
11711               ln.push_back(ln1[1]);
11712               ln.push_back(ln1[2]);
11713               ln.push_back(ln1[3]);
11714               ln.push_back(ln3[0]);
11715               ln.push_back(ln3[1]);
11716               ln.push_back(ln3[2]);
11717               ln.push_back(ln3[3]);
11718               break;
11719             case VTK_POLYGON:
11720               break;
11721             default:
11722               break;
11723           }
11724
11725           if (vol)
11726             {
11727               stringstream grpname;
11728               grpname << "jf_";
11729               grpname << idom;
11730               int idg;
11731               string namegrp = grpname.str();
11732               if (!mapOfJunctionGroups.count(namegrp))
11733                 mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
11734               SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11735               if (sgrp)
11736                 sgrp->Add(vol->GetID());
11737             }
11738
11739           // --- modify the face
11740
11741           aFace->ChangeNodes(&ln[0], ln.size());
11742         }
11743     }
11744   return true;
11745 }
11746
11747 /*!
11748  *  \brief identify all the elements around a geom shape, get the faces delimiting the hole
11749  *  Build groups of volume to remove, groups of faces to replace on the skin of the object,
11750  *  groups of faces to remove inside the object, (idem edges).
11751  *  Build ordered list of nodes at the border of each group of faces to replace (to be used to build a geom subshape)
11752  */
11753 void SMESH_MeshEditor::CreateHoleSkin(double radius,
11754                                       const TopoDS_Shape& theShape,
11755                                       SMESH_NodeSearcher* theNodeSearcher,
11756                                       const char* groupName,
11757                                       std::vector<double>&   nodesCoords,
11758                                       std::vector<std::vector<int> >& listOfListOfNodes)
11759 {
11760   MESSAGE("--------------------------------");
11761   MESSAGE("SMESH_MeshEditor::CreateHoleSkin");
11762   MESSAGE("--------------------------------");
11763
11764   // --- zone of volumes to remove is given :
11765   //     1 either by a geom shape (one or more vertices) and a radius,
11766   //     2 either by a group of nodes (representative of the shape)to use with the radius,
11767   //     3 either by a group of nodes where all the elements build on one of this nodes are to remove,
11768   //     In the case 2, the group of nodes is an external group of nodes from another mesh,
11769   //     In the case 3, the group of nodes is an internal group of the mesh (obtained for instance by a filter),
11770   //     defined by it's name.
11771
11772   SMESHDS_GroupBase* groupDS = 0;
11773   SMESH_Mesh::GroupIteratorPtr groupIt = this->myMesh->GetGroups();
11774   while ( groupIt->more() )
11775     {
11776       groupDS = 0;
11777       SMESH_Group * group = groupIt->next();
11778       if ( !group ) continue;
11779       groupDS = group->GetGroupDS();
11780       if ( !groupDS || groupDS->IsEmpty() ) continue;
11781       std::string grpName = group->GetName();
11782       if (grpName == groupName)
11783         break;
11784     }
11785
11786   bool isNodeGroup = false;
11787   bool isNodeCoords = false;
11788   if (groupDS)
11789     {
11790       if (groupDS->GetType() != SMDSAbs_Node)
11791         return;
11792       isNodeGroup = true;     // a group of nodes exists and it is in this mesh
11793     }
11794
11795   if (nodesCoords.size() > 0)
11796     isNodeCoords = true; // a list o nodes given by their coordinates
11797
11798   // --- define groups to build
11799
11800   int idg; // --- group of SMDS volumes
11801   string grpvName = groupName;
11802   grpvName += "_vol";
11803   SMESH_Group *grp = this->myMesh->AddGroup(SMDSAbs_Volume, grpvName.c_str(), idg);
11804   if (!grp)
11805     {
11806       MESSAGE("group not created " << grpvName);
11807       return;
11808     }
11809   SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(grp->GetGroupDS());
11810
11811   int idgs; // --- group of SMDS faces on the skin
11812   string grpsName = groupName;
11813   grpsName += "_skin";
11814   SMESH_Group *grps = this->myMesh->AddGroup(SMDSAbs_Face, grpsName.c_str(), idgs);
11815   if (!grps)
11816     {
11817       MESSAGE("group not created " << grpsName);
11818       return;
11819     }
11820   SMESHDS_Group *sgrps = dynamic_cast<SMESHDS_Group*>(grps->GetGroupDS());
11821
11822   int idgi; // --- group of SMDS faces internal (several shapes)
11823   string grpiName = groupName;
11824   grpiName += "_internalFaces";
11825   SMESH_Group *grpi = this->myMesh->AddGroup(SMDSAbs_Face, grpiName.c_str(), idgi);
11826   if (!grpi)
11827     {
11828       MESSAGE("group not created " << grpiName);
11829       return;
11830     }
11831   SMESHDS_Group *sgrpi = dynamic_cast<SMESHDS_Group*>(grpi->GetGroupDS());
11832
11833   int idgei; // --- group of SMDS faces internal (several shapes)
11834   string grpeiName = groupName;
11835   grpeiName += "_internalEdges";
11836   SMESH_Group *grpei = this->myMesh->AddGroup(SMDSAbs_Edge, grpeiName.c_str(), idgei);
11837   if (!grpei)
11838     {
11839       MESSAGE("group not created " << grpeiName);
11840       return;
11841     }
11842   SMESHDS_Group *sgrpei = dynamic_cast<SMESHDS_Group*>(grpei->GetGroupDS());
11843
11844   // --- build downward connectivity
11845
11846   SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
11847   meshDS->BuildDownWardConnectivity(true);
11848   SMDS_UnstructuredGrid* grid = meshDS->getGrid();
11849
11850   // --- set of volumes detected inside
11851
11852   std::set<int> setOfInsideVol;
11853   std::set<int> setOfVolToCheck;
11854
11855   std::vector<gp_Pnt> gpnts;
11856   gpnts.clear();
11857
11858   if (isNodeGroup) // --- a group of nodes is provided : find all the volumes using one or more of this nodes
11859     {
11860       MESSAGE("group of nodes provided");
11861       SMDS_ElemIteratorPtr elemIt = groupDS->GetElements();
11862       while ( elemIt->more() )
11863         {
11864           const SMDS_MeshElement* elem = elemIt->next();
11865           if (!elem)
11866             continue;
11867           const SMDS_MeshNode* node = dynamic_cast<const SMDS_MeshNode*>(elem);
11868           if (!node)
11869             continue;
11870           SMDS_MeshElement* vol = 0;
11871           SMDS_ElemIteratorPtr volItr = node->GetInverseElementIterator(SMDSAbs_Volume);
11872           while (volItr->more())
11873             {
11874               vol = (SMDS_MeshElement*)volItr->next();
11875               setOfInsideVol.insert(vol->getVtkId());
11876               sgrp->Add(vol->GetID());
11877             }
11878         }
11879     }
11880   else if (isNodeCoords)
11881     {
11882       MESSAGE("list of nodes coordinates provided");
11883       int i = 0;
11884       int k = 0;
11885       while (i < nodesCoords.size()-2)
11886         {
11887           double x = nodesCoords[i++];
11888           double y = nodesCoords[i++];
11889           double z = nodesCoords[i++];
11890           gp_Pnt p = gp_Pnt(x, y ,z);
11891           gpnts.push_back(p);
11892           MESSAGE("TopoDS_Vertex " << k++ << " " << p.X() << " " << p.Y() << " " << p.Z());
11893         }
11894     }
11895   else // --- no group, no coordinates : use the vertices of the geom shape provided, and radius
11896     {
11897       MESSAGE("no group of nodes provided, using vertices from geom shape, and radius");
11898       TopTools_IndexedMapOfShape vertexMap;
11899       TopExp::MapShapes( theShape, TopAbs_VERTEX, vertexMap );
11900       gp_Pnt p = gp_Pnt(0,0,0);
11901       if (vertexMap.Extent() < 1)
11902         return;
11903
11904       for ( int i = 1; i <= vertexMap.Extent(); ++i )
11905         {
11906           const TopoDS_Vertex& vertex = TopoDS::Vertex( vertexMap( i ));
11907           p = BRep_Tool::Pnt(vertex);
11908           gpnts.push_back(p);
11909           MESSAGE("TopoDS_Vertex " << i << " " << p.X() << " " << p.Y() << " " << p.Z());
11910         }
11911     }
11912
11913   if (gpnts.size() > 0)
11914     {
11915       int nodeId = 0;
11916       const SMDS_MeshNode* startNode = theNodeSearcher->FindClosestTo(gpnts[0]);
11917       if (startNode)
11918         nodeId = startNode->GetID();
11919       MESSAGE("nodeId " << nodeId);
11920
11921       double radius2 = radius*radius;
11922       MESSAGE("radius2 " << radius2);
11923
11924       // --- volumes on start node
11925
11926       setOfVolToCheck.clear();
11927       SMDS_MeshElement* startVol = 0;
11928       SMDS_ElemIteratorPtr volItr = startNode->GetInverseElementIterator(SMDSAbs_Volume);
11929       while (volItr->more())
11930         {
11931           startVol = (SMDS_MeshElement*)volItr->next();
11932           setOfVolToCheck.insert(startVol->getVtkId());
11933         }
11934       if (setOfVolToCheck.empty())
11935         {
11936           MESSAGE("No volumes found");
11937           return;
11938         }
11939
11940       // --- starting with central volumes then their neighbors, check if they are inside
11941       //     or outside the domain, until no more new neighbor volume is inside.
11942       //     Fill the group of inside volumes
11943
11944       std::map<int, double> mapOfNodeDistance2;
11945       mapOfNodeDistance2.clear();
11946       std::set<int> setOfOutsideVol;
11947       while (!setOfVolToCheck.empty())
11948         {
11949           std::set<int>::iterator it = setOfVolToCheck.begin();
11950           int vtkId = *it;
11951           MESSAGE("volume to check,  vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId));
11952           bool volInside = false;
11953           vtkIdType npts = 0;
11954           vtkIdType* pts = 0;
11955           grid->GetCellPoints(vtkId, npts, pts);
11956           for (int i=0; i<npts; i++)
11957             {
11958               double distance2 = 0;
11959               if (mapOfNodeDistance2.count(pts[i]))
11960                 {
11961                   distance2 = mapOfNodeDistance2[pts[i]];
11962                   MESSAGE("point " << pts[i] << " distance2 " << distance2);
11963                 }
11964               else
11965                 {
11966                   double *coords = grid->GetPoint(pts[i]);
11967                   gp_Pnt aPoint = gp_Pnt(coords[0], coords[1], coords[2]);
11968                   distance2 = 1.E40;
11969                   for (int j=0; j<gpnts.size(); j++)
11970                     {
11971                       double d2 = aPoint.SquareDistance(gpnts[j]);
11972                       if (d2 < distance2)
11973                         {
11974                           distance2 = d2;
11975                           if (distance2 < radius2)
11976                             break;
11977                         }
11978                     }
11979                   mapOfNodeDistance2[pts[i]] = distance2;
11980                   MESSAGE("  point "  << pts[i]  << " distance2 " << distance2 << " coords " << coords[0] << " " << coords[1] << " " <<  coords[2]);
11981                 }
11982               if (distance2 < radius2)
11983                 {
11984                   volInside = true; // one or more nodes inside the domain
11985                   sgrp->Add(meshDS->fromVtkToSmds(vtkId));
11986                   break;
11987                 }
11988             }
11989           if (volInside)
11990             {
11991               setOfInsideVol.insert(vtkId);
11992               MESSAGE("  volume inside,  vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId));
11993               int neighborsVtkIds[NBMAXNEIGHBORS];
11994               int downIds[NBMAXNEIGHBORS];
11995               unsigned char downTypes[NBMAXNEIGHBORS];
11996               int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
11997               for (int n = 0; n < nbNeighbors; n++)
11998                 if (!setOfInsideVol.count(neighborsVtkIds[n]) ||setOfOutsideVol.count(neighborsVtkIds[n]))
11999                   setOfVolToCheck.insert(neighborsVtkIds[n]);
12000             }
12001           else
12002             {
12003               setOfOutsideVol.insert(vtkId);
12004               MESSAGE("  volume outside, vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId));
12005             }
12006           setOfVolToCheck.erase(vtkId);
12007         }
12008     }
12009
12010   // --- for outside hexahedrons, check if they have more than one neighbor volume inside
12011   //     If yes, add the volume to the inside set
12012
12013   bool addedInside = true;
12014   std::set<int> setOfVolToReCheck;
12015   while (addedInside)
12016     {
12017       MESSAGE(" --------------------------- re check");
12018       addedInside = false;
12019       std::set<int>::iterator itv = setOfInsideVol.begin();
12020       for (; itv != setOfInsideVol.end(); ++itv)
12021         {
12022           int vtkId = *itv;
12023           int neighborsVtkIds[NBMAXNEIGHBORS];
12024           int downIds[NBMAXNEIGHBORS];
12025           unsigned char downTypes[NBMAXNEIGHBORS];
12026           int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
12027           for (int n = 0; n < nbNeighbors; n++)
12028             if (!setOfInsideVol.count(neighborsVtkIds[n]))
12029               setOfVolToReCheck.insert(neighborsVtkIds[n]);
12030         }
12031       setOfVolToCheck = setOfVolToReCheck;
12032       setOfVolToReCheck.clear();
12033       while  (!setOfVolToCheck.empty())
12034         {
12035           std::set<int>::iterator it = setOfVolToCheck.begin();
12036           int vtkId = *it;
12037           if (grid->GetCellType(vtkId) == VTK_HEXAHEDRON)
12038             {
12039               MESSAGE("volume to recheck,  vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId));
12040               int countInside = 0;
12041               int neighborsVtkIds[NBMAXNEIGHBORS];
12042               int downIds[NBMAXNEIGHBORS];
12043               unsigned char downTypes[NBMAXNEIGHBORS];
12044               int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
12045               for (int n = 0; n < nbNeighbors; n++)
12046                 if (setOfInsideVol.count(neighborsVtkIds[n]))
12047                   countInside++;
12048               MESSAGE("countInside " << countInside);
12049               if (countInside > 1)
12050                 {
12051                   MESSAGE("  volume inside,  vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId));
12052                   setOfInsideVol.insert(vtkId);
12053                   sgrp->Add(meshDS->fromVtkToSmds(vtkId));
12054                   addedInside = true;
12055                 }
12056               else
12057                 setOfVolToReCheck.insert(vtkId);
12058             }
12059           setOfVolToCheck.erase(vtkId);
12060         }
12061     }
12062
12063   // --- map of Downward faces at the boundary, inside the global volume
12064   //     map of Downward faces on the skin of the global volume (equivalent to SMDS faces on the skin)
12065   //     fill group of SMDS faces inside the volume (when several volume shapes)
12066   //     fill group of SMDS faces on the skin of the global volume (if skin)
12067
12068   std::map<DownIdType, int, DownIdCompare> boundaryFaces; // boundary faces inside the volume --> corresponding cell
12069   std::map<DownIdType, int, DownIdCompare> skinFaces;     // faces on the skin of the global volume --> corresponding cell
12070   std::set<int>::iterator it = setOfInsideVol.begin();
12071   for (; it != setOfInsideVol.end(); ++it)
12072     {
12073       int vtkId = *it;
12074       //MESSAGE("  vtkId " << vtkId  << " smdsId " << meshDS->fromVtkToSmds(vtkId));
12075       int neighborsVtkIds[NBMAXNEIGHBORS];
12076       int downIds[NBMAXNEIGHBORS];
12077       unsigned char downTypes[NBMAXNEIGHBORS];
12078       int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId, true);
12079       for (int n = 0; n < nbNeighbors; n++)
12080         {
12081           int neighborDim = SMDS_Downward::getCellDimension(grid->GetCellType(neighborsVtkIds[n]));
12082           if (neighborDim == 3)
12083             {
12084               if (! setOfInsideVol.count(neighborsVtkIds[n])) // neighbor volume is not inside : face is boundary
12085                 {
12086                   DownIdType face(downIds[n], downTypes[n]);
12087                   boundaryFaces[face] = vtkId;
12088                 }
12089               // if the face between to volumes is in the mesh, get it (internal face between shapes)
12090               int vtkFaceId = grid->getDownArray(downTypes[n])->getVtkCellId(downIds[n]);
12091               if (vtkFaceId >= 0)
12092                 {
12093                   sgrpi->Add(meshDS->fromVtkToSmds(vtkFaceId));
12094                   // find also the smds edges on this face
12095                   int nbEdges = grid->getDownArray(downTypes[n])->getNumberOfDownCells(downIds[n]);
12096                   const int* dEdges = grid->getDownArray(downTypes[n])->getDownCells(downIds[n]);
12097                   const unsigned char* dTypes = grid->getDownArray(downTypes[n])->getDownTypes(downIds[n]);
12098                   for (int i = 0; i < nbEdges; i++)
12099                     {
12100                       int vtkEdgeId = grid->getDownArray(dTypes[i])->getVtkCellId(dEdges[i]);
12101                       if (vtkEdgeId >= 0)
12102                         sgrpei->Add(meshDS->fromVtkToSmds(vtkEdgeId));
12103                     }
12104                 }
12105             }
12106           else if (neighborDim == 2) // skin of the volume
12107             {
12108               DownIdType face(downIds[n], downTypes[n]);
12109               skinFaces[face] = vtkId;
12110               int vtkFaceId = grid->getDownArray(downTypes[n])->getVtkCellId(downIds[n]);
12111               if (vtkFaceId >= 0)
12112                 sgrps->Add(meshDS->fromVtkToSmds(vtkFaceId));
12113             }
12114         }
12115     }
12116
12117   // --- identify the edges constituting the wire of each subshape on the skin
12118   //     define polylines with the nodes of edges, equivalent to wires
12119   //     project polylines on subshapes, and partition, to get geom faces
12120
12121   std::map<int, std::set<int> > shapeIdToVtkIdSet; // shapeId --> set of vtkId on skin
12122   std::set<int> emptySet;
12123   emptySet.clear();
12124   std::set<int> shapeIds;
12125
12126   SMDS_ElemIteratorPtr itelem = sgrps->GetElements();
12127   while (itelem->more())
12128     {
12129       const SMDS_MeshElement *elem = itelem->next();
12130       int shapeId = elem->getshapeId();
12131       int vtkId = elem->getVtkId();
12132       if (!shapeIdToVtkIdSet.count(shapeId))
12133         {
12134           shapeIdToVtkIdSet[shapeId] = emptySet;
12135           shapeIds.insert(shapeId);
12136         }
12137       shapeIdToVtkIdSet[shapeId].insert(vtkId);
12138     }
12139
12140   std::map<int, std::set<DownIdType, DownIdCompare> > shapeIdToEdges; // shapeId --> set of downward edges
12141   std::set<DownIdType, DownIdCompare> emptyEdges;
12142   emptyEdges.clear();
12143
12144   std::map<int, std::set<int> >::iterator itShape =  shapeIdToVtkIdSet.begin();
12145   for (; itShape != shapeIdToVtkIdSet.end(); ++itShape)
12146     {
12147       int shapeId = itShape->first;
12148       MESSAGE(" --- Shape ID --- "<< shapeId);
12149       shapeIdToEdges[shapeId] = emptyEdges;
12150
12151       std::vector<int> nodesEdges;
12152
12153       std::set<int>::iterator its = itShape->second.begin();
12154       for (; its != itShape->second.end(); ++its)
12155         {
12156           int vtkId = *its;
12157           MESSAGE("     " << vtkId);
12158           int neighborsVtkIds[NBMAXNEIGHBORS];
12159           int downIds[NBMAXNEIGHBORS];
12160           unsigned char downTypes[NBMAXNEIGHBORS];
12161           int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
12162           for (int n = 0; n < nbNeighbors; n++)
12163             {
12164               if (neighborsVtkIds[n]<0) // only smds faces are considered as neighbors here
12165                 continue;
12166               int smdsId = meshDS->fromVtkToSmds(neighborsVtkIds[n]);
12167               const SMDS_MeshElement* elem = meshDS->FindElement(smdsId);
12168               if ( shapeIds.count(elem->getshapeId()) && !sgrps->Contains(elem)) // edge : neighbor in the set of shape, not in the group
12169                 {
12170                   DownIdType edge(downIds[n], downTypes[n]);
12171                   if (!shapeIdToEdges[shapeId].count(edge))
12172                     {
12173                       shapeIdToEdges[shapeId].insert(edge);
12174                       int vtkNodeId[3];
12175                       int nbNodes = grid->getDownArray(downTypes[n])->getNodes(downIds[n],vtkNodeId);
12176                       nodesEdges.push_back(vtkNodeId[0]);
12177                       nodesEdges.push_back(vtkNodeId[nbNodes-1]);
12178                       MESSAGE("       --- nodes " << vtkNodeId[0]+1 << " " << vtkNodeId[nbNodes-1]+1);
12179                     }
12180                 }
12181             }
12182         }
12183
12184       std::list<int> order;
12185       order.clear();
12186       if (nodesEdges.size() > 0)
12187         {
12188           order.push_back(nodesEdges[0]); MESSAGE("       --- back " << order.back()+1); // SMDS id = VTK id + 1;
12189           nodesEdges[0] = -1;
12190           order.push_back(nodesEdges[1]); MESSAGE("       --- back " << order.back()+1);
12191           nodesEdges[1] = -1; // do not reuse this edge
12192           bool found = true;
12193           while (found)
12194             {
12195               int nodeTofind = order.back(); // try first to push back
12196               int i = 0;
12197               for (i = 0; i<nodesEdges.size(); i++)
12198                 if (nodesEdges[i] == nodeTofind)
12199                   break;
12200               if (i == nodesEdges.size())
12201                 found = false; // no follower found on back
12202               else
12203                 {
12204                   if (i%2) // odd ==> use the previous one
12205                     if (nodesEdges[i-1] < 0)
12206                       found = false;
12207                     else
12208                       {
12209                         order.push_back(nodesEdges[i-1]); MESSAGE("       --- back " << order.back()+1);
12210                         nodesEdges[i-1] = -1;
12211                       }
12212                   else // even ==> use the next one
12213                     if (nodesEdges[i+1] < 0)
12214                       found = false;
12215                     else
12216                       {
12217                         order.push_back(nodesEdges[i+1]); MESSAGE("       --- back " << order.back()+1);
12218                         nodesEdges[i+1] = -1;
12219                       }
12220                 }
12221               if (found)
12222                 continue;
12223               // try to push front
12224               found = true;
12225               nodeTofind = order.front(); // try to push front
12226               for (i = 0; i<nodesEdges.size(); i++)
12227                 if (nodesEdges[i] == nodeTofind)
12228                   break;
12229               if (i == nodesEdges.size())
12230                 {
12231                   found = false; // no predecessor found on front
12232                   continue;
12233                 }
12234               if (i%2) // odd ==> use the previous one
12235                 if (nodesEdges[i-1] < 0)
12236                   found = false;
12237                 else
12238                   {
12239                     order.push_front(nodesEdges[i-1]); MESSAGE("       --- front " << order.front()+1);
12240                     nodesEdges[i-1] = -1;
12241                   }
12242               else // even ==> use the next one
12243                 if (nodesEdges[i+1] < 0)
12244                   found = false;
12245                 else
12246                   {
12247                     order.push_front(nodesEdges[i+1]); MESSAGE("       --- front " << order.front()+1);
12248                     nodesEdges[i+1] = -1;
12249                   }
12250             }
12251         }
12252
12253
12254       std::vector<int> nodes;
12255       nodes.push_back(shapeId);
12256       std::list<int>::iterator itl = order.begin();
12257       for (; itl != order.end(); itl++)
12258         {
12259           nodes.push_back((*itl) + 1); // SMDS id = VTK id + 1;
12260           MESSAGE("              ordered node " << nodes[nodes.size()-1]);
12261         }
12262       listOfListOfNodes.push_back(nodes);
12263     }
12264
12265   //     partition geom faces with blocFissure
12266   //     mesh blocFissure and geom faces of the skin (external wires given, triangle algo to choose)
12267   //     mesh volume around blocFissure (skin triangles and quadrangle given, tetra algo to choose)
12268
12269   return;
12270 }
12271
12272
12273 //================================================================================
12274 /*!
12275  * \brief Generates skin mesh (containing 2D cells) from 3D mesh
12276  * The created 2D mesh elements based on nodes of free faces of boundary volumes
12277  * \return TRUE if operation has been completed successfully, FALSE otherwise
12278  */
12279 //================================================================================
12280
12281 bool SMESH_MeshEditor::Make2DMeshFrom3D()
12282 {
12283   // iterates on volume elements and detect all free faces on them
12284   SMESHDS_Mesh* aMesh = GetMeshDS();
12285   if (!aMesh)
12286     return false;
12287   //bool res = false;
12288   int nbFree = 0, nbExisted = 0, nbCreated = 0;
12289   SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator();
12290   while(vIt->more())
12291   {
12292     const SMDS_MeshVolume* volume = vIt->next();
12293     SMDS_VolumeTool vTool( volume, /*ignoreCentralNodes=*/false );
12294     vTool.SetExternalNormal();
12295     //const bool isPoly = volume->IsPoly();
12296     const int iQuad = volume->IsQuadratic();
12297     for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
12298     {
12299       if (!vTool.IsFreeFace(iface))
12300         continue;
12301       nbFree++;
12302       vector<const SMDS_MeshNode *> nodes;
12303       int nbFaceNodes = vTool.NbFaceNodes(iface);
12304       const SMDS_MeshNode** faceNodes = vTool.GetFaceNodes(iface);
12305       int inode = 0;
12306       for ( ; inode < nbFaceNodes; inode += iQuad+1)
12307         nodes.push_back(faceNodes[inode]);
12308       if (iQuad) { // add medium nodes
12309         for ( inode = 1; inode < nbFaceNodes; inode += 2)
12310           nodes.push_back(faceNodes[inode]);
12311         if ( nbFaceNodes == 9 ) // bi-quadratic quad
12312           nodes.push_back(faceNodes[8]);
12313       }
12314       // add new face based on volume nodes
12315       if (aMesh->FindElement( nodes, SMDSAbs_Face, /*noMedium=*/false) ) {
12316         nbExisted++;
12317         continue; // face already exsist
12318       }
12319       AddElement(nodes, SMDSAbs_Face, ( !iQuad && nbFaceNodes/(iQuad+1) > 4 ));
12320       nbCreated++;
12321     }
12322   }
12323   return ( nbFree==(nbExisted+nbCreated) );
12324 }
12325
12326 namespace
12327 {
12328   inline const SMDS_MeshNode* getNodeWithSameID(SMESHDS_Mesh* mesh, const SMDS_MeshNode* node)
12329   {
12330     if ( const SMDS_MeshNode* n = mesh->FindNode( node->GetID() ))
12331       return n;
12332     return mesh->AddNodeWithID( node->X(),node->Y(),node->Z(), node->GetID() );
12333   }
12334 }
12335 //================================================================================
12336 /*!
12337  * \brief Creates missing boundary elements
12338  *  \param elements - elements whose boundary is to be checked
12339  *  \param dimension - defines type of boundary elements to create
12340  *  \param group - a group to store created boundary elements in
12341  *  \param targetMesh - a mesh to store created boundary elements in
12342  *  \param toCopyElements - if true, the checked elements will be copied into the targetMesh
12343  *  \param toCopyExistingBoundary - if true, not only new but also pre-existing
12344  *                                boundary elements will be copied into the targetMesh
12345  *  \param toAddExistingBondary - if true, not only new but also pre-existing
12346  *                                boundary elements will be added into the new group
12347  *  \param aroundElements - if true, elements will be created on boundary of given
12348  *                          elements else, on boundary of the whole mesh.
12349  * \return nb of added boundary elements
12350  */
12351 //================================================================================
12352
12353 int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
12354                                        Bnd_Dimension           dimension,
12355                                        SMESH_Group*            group/*=0*/,
12356                                        SMESH_Mesh*             targetMesh/*=0*/,
12357                                        bool                    toCopyElements/*=false*/,
12358                                        bool                    toCopyExistingBoundary/*=false*/,
12359                                        bool                    toAddExistingBondary/*= false*/,
12360                                        bool                    aroundElements/*= false*/)
12361 {
12362   SMDSAbs_ElementType missType = (dimension == BND_2DFROM3D) ? SMDSAbs_Face : SMDSAbs_Edge;
12363   SMDSAbs_ElementType elemType = (dimension == BND_1DFROM2D) ? SMDSAbs_Face : SMDSAbs_Volume;
12364   // hope that all elements are of the same type, do not check them all
12365   if ( !elements.empty() && (*elements.begin())->GetType() != elemType )
12366     throw SALOME_Exception(LOCALIZED("wrong element type"));
12367
12368   if ( !targetMesh )
12369     toCopyElements = toCopyExistingBoundary = false;
12370
12371   SMESH_MeshEditor tgtEditor( targetMesh ? targetMesh : myMesh );
12372   SMESHDS_Mesh* aMesh = GetMeshDS(), *tgtMeshDS = tgtEditor.GetMeshDS();
12373   int nbAddedBnd = 0;
12374
12375   // editor adding present bnd elements and optionally holding elements to add to the group
12376   SMESH_MeshEditor* presentEditor;
12377   SMESH_MeshEditor tgtEditor2( tgtEditor.GetMesh() );
12378   presentEditor = toAddExistingBondary ? &tgtEditor : &tgtEditor2;
12379
12380   SMESH_MesherHelper helper( *myMesh );
12381   const TopAbs_ShapeEnum missShapeType = ( missType==SMDSAbs_Face ? TopAbs_FACE : TopAbs_EDGE );
12382   SMDS_VolumeTool vTool;
12383   TIDSortedElemSet avoidSet;
12384   const TIDSortedElemSet emptySet, *elemSet = aroundElements ? &elements : &emptySet;
12385   int inode;
12386
12387   typedef vector<const SMDS_MeshNode*> TConnectivity;
12388
12389   SMDS_ElemIteratorPtr eIt;
12390   if (elements.empty())
12391     eIt = aMesh->elementsIterator(elemType);
12392   else
12393     eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
12394
12395   while (eIt->more())
12396   {
12397     const SMDS_MeshElement* elem = eIt->next();
12398     const int iQuad = elem->IsQuadratic();
12399
12400     // ------------------------------------------------------------------------------------
12401     // 1. For an elem, get present bnd elements and connectivities of missing bnd elements
12402     // ------------------------------------------------------------------------------------
12403     vector<const SMDS_MeshElement*> presentBndElems;
12404     vector<TConnectivity>           missingBndElems;
12405     TConnectivity nodes;
12406     if ( vTool.Set(elem, /*ignoreCentralNodes=*/true) ) // elem is a volume --------------
12407     {
12408       vTool.SetExternalNormal();
12409       const SMDS_MeshElement* otherVol = 0;
12410       for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
12411       {
12412         if ( !vTool.IsFreeFace(iface, &otherVol) &&
12413              ( !aroundElements || elements.count( otherVol )))
12414           continue;
12415         const int nbFaceNodes = vTool.NbFaceNodes(iface);
12416         const SMDS_MeshNode** nn = vTool.GetFaceNodes(iface);
12417         if ( missType == SMDSAbs_Edge ) // boundary edges
12418         {
12419           nodes.resize( 2+iQuad );
12420           for ( int i = 0; i < nbFaceNodes; i += 1+iQuad)
12421           {
12422             for ( int j = 0; j < nodes.size(); ++j )
12423               nodes[j] =nn[i+j];
12424             if ( const SMDS_MeshElement* edge =
12425                  aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/false))
12426               presentBndElems.push_back( edge );
12427             else
12428               missingBndElems.push_back( nodes );
12429           }
12430         }
12431         else // boundary face
12432         {
12433           nodes.clear();
12434           for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
12435             nodes.push_back( nn[inode] );
12436           if (iQuad) // add medium nodes
12437             for ( inode = 1; inode < nbFaceNodes; inode += 2)
12438               nodes.push_back( nn[inode] );
12439           int iCenter = vTool.GetCenterNodeIndex(iface); // for HEX27
12440           if ( iCenter > 0 )
12441             nodes.push_back( vTool.GetNodes()[ iCenter ] );
12442
12443           if (const SMDS_MeshElement * f = aMesh->FindElement( nodes,
12444                                                                SMDSAbs_Face, /*noMedium=*/false ))
12445             presentBndElems.push_back( f );
12446           else
12447             missingBndElems.push_back( nodes );
12448
12449           if ( targetMesh != myMesh )
12450           {
12451             // add 1D elements on face boundary to be added to a new mesh
12452             const SMDS_MeshElement* edge;
12453             for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
12454             {
12455               if ( iQuad )
12456                 edge = aMesh->FindEdge( nn[inode], nn[inode+1], nn[inode+2]);
12457               else
12458                 edge = aMesh->FindEdge( nn[inode], nn[inode+1]);
12459               if ( edge && avoidSet.insert( edge ).second )
12460                 presentBndElems.push_back( edge );
12461             }
12462           }
12463         }
12464       }
12465     }
12466     else                     // elem is a face ------------------------------------------
12467     {
12468       avoidSet.clear(), avoidSet.insert( elem );
12469       int nbNodes = elem->NbCornerNodes();
12470       nodes.resize( 2 /*+ iQuad*/);
12471       for ( int i = 0; i < nbNodes; i++ )
12472       {
12473         nodes[0] = elem->GetNode(i);
12474         nodes[1] = elem->GetNode((i+1)%nbNodes);
12475         if ( FindFaceInSet( nodes[0], nodes[1], *elemSet, avoidSet))
12476           continue; // not free link
12477
12478         //if ( iQuad )
12479         //nodes[2] = elem->GetNode( i + nbNodes );
12480         if ( const SMDS_MeshElement* edge =
12481              aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/true))
12482           presentBndElems.push_back( edge );
12483         else
12484           missingBndElems.push_back( nodes );
12485       }
12486     }
12487
12488     // ---------------------------------
12489     // 2. Add missing boundary elements
12490     // ---------------------------------
12491     if ( targetMesh != myMesh )
12492       // instead of making a map of nodes in this mesh and targetMesh,
12493       // we create nodes with same IDs.
12494       for ( int i = 0; i < missingBndElems.size(); ++i )
12495       {
12496         TConnectivity& srcNodes = missingBndElems[i];
12497         TConnectivity  nodes( srcNodes.size() );
12498         for ( inode = 0; inode < nodes.size(); ++inode )
12499           nodes[inode] = getNodeWithSameID( tgtMeshDS, srcNodes[inode] );
12500         if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes,
12501                                                                    missType,
12502                                                                    /*noMedium=*/false))
12503           continue;
12504         tgtEditor.AddElement(nodes, missType, !iQuad && nodes.size()/(iQuad+1)>4);
12505         ++nbAddedBnd;
12506       }
12507     else
12508       for ( int i = 0; i < missingBndElems.size(); ++i )
12509       {
12510         TConnectivity& nodes = missingBndElems[i];
12511         if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes,
12512                                                                    missType,
12513                                                                    /*noMedium=*/false))
12514           continue;
12515         SMDS_MeshElement* elem =
12516           tgtEditor.AddElement(nodes, missType, !iQuad && nodes.size()/(iQuad+1)>4);
12517         ++nbAddedBnd;
12518
12519         // try to set a new element to a shape
12520         if ( myMesh->HasShapeToMesh() )
12521         {
12522           bool ok = true;
12523           set< pair<TopAbs_ShapeEnum, int > > mediumShapes;
12524           const int nbN = nodes.size() / (iQuad+1 );
12525           for ( inode = 0; inode < nbN && ok; ++inode )
12526           {
12527             pair<int, TopAbs_ShapeEnum> i_stype =
12528               helper.GetMediumPos( nodes[inode], nodes[(inode+1)%nbN]);
12529             if (( ok = ( i_stype.first > 0 && i_stype.second >= TopAbs_FACE )))
12530               mediumShapes.insert( make_pair ( i_stype.second, i_stype.first ));
12531           }
12532           if ( ok && mediumShapes.size() > 1 )
12533           {
12534             set< pair<TopAbs_ShapeEnum, int > >::iterator stype_i = mediumShapes.begin();
12535             pair<TopAbs_ShapeEnum, int> stype_i_0 = *stype_i;
12536             for ( ++stype_i; stype_i != mediumShapes.end() && ok; ++stype_i )
12537             {
12538               if (( ok = ( stype_i->first != stype_i_0.first )))
12539                 ok = helper.IsSubShape( aMesh->IndexToShape( stype_i->second ),
12540                                         aMesh->IndexToShape( stype_i_0.second ));
12541             }
12542           }
12543           if ( ok && mediumShapes.begin()->first == missShapeType )
12544             aMesh->SetMeshElementOnShape( elem, mediumShapes.begin()->second );
12545         }
12546       }
12547
12548     // ----------------------------------
12549     // 3. Copy present boundary elements
12550     // ----------------------------------
12551     if ( toCopyExistingBoundary )
12552       for ( int i = 0 ; i < presentBndElems.size(); ++i )
12553       {
12554         const SMDS_MeshElement* e = presentBndElems[i];
12555         TConnectivity nodes( e->NbNodes() );
12556         for ( inode = 0; inode < nodes.size(); ++inode )
12557           nodes[inode] = getNodeWithSameID( tgtMeshDS, e->GetNode(inode) );
12558         presentEditor->AddElement(nodes, e->GetType(), e->IsPoly());
12559       }
12560     else // store present elements to add them to a group
12561       for ( int i = 0 ; i < presentBndElems.size(); ++i )
12562       {
12563         presentEditor->myLastCreatedElems.Append(presentBndElems[i]);
12564       }
12565
12566   } // loop on given elements
12567
12568   // ---------------------------------------------
12569   // 4. Fill group with boundary elements
12570   // ---------------------------------------------
12571   if ( group )
12572   {
12573     if ( SMESHDS_Group* g = dynamic_cast<SMESHDS_Group*>( group->GetGroupDS() ))
12574       for ( int i = 0; i < tgtEditor.myLastCreatedElems.Size(); ++i )
12575         g->SMDSGroup().Add( tgtEditor.myLastCreatedElems( i+1 ));
12576   }
12577   tgtEditor.myLastCreatedElems.Clear();
12578   tgtEditor2.myLastCreatedElems.Clear();
12579
12580   // -----------------------
12581   // 5. Copy given elements
12582   // -----------------------
12583   if ( toCopyElements && targetMesh != myMesh )
12584   {
12585     if (elements.empty())
12586       eIt = aMesh->elementsIterator(elemType);
12587     else
12588       eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
12589     while (eIt->more())
12590     {
12591       const SMDS_MeshElement* elem = eIt->next();
12592       TConnectivity nodes( elem->NbNodes() );
12593       for ( inode = 0; inode < nodes.size(); ++inode )
12594         nodes[inode] = getNodeWithSameID( tgtMeshDS, elem->GetNode(inode) );
12595       tgtEditor.AddElement(nodes, elemType, elem->IsPoly());
12596
12597       tgtEditor.myLastCreatedElems.Clear();
12598     }
12599   }
12600   return nbAddedBnd;
12601 }