Salome HOME
Update copyright information
[modules/smesh.git] / src / SMESH / SMESH_MeshEditor.cxx
1 // Copyright (C) 2007-2012  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22
23 // SMESH SMESH : idl implementation based on 'SMESH' unit's classes
24 // File      : SMESH_MeshEditor.cxx
25 // Created   : Mon Apr 12 16:10:22 2004
26 // Author    : Edward AGAPOV (eap)
27
28 #include "SMESH_MeshEditor.hxx"
29
30 #include "SMDS_FaceOfNodes.hxx"
31 #include "SMDS_VolumeTool.hxx"
32 #include "SMDS_EdgePosition.hxx"
33 #include "SMDS_FacePosition.hxx"
34 #include "SMDS_SpacePosition.hxx"
35 #include "SMDS_MeshGroup.hxx"
36 #include "SMDS_LinearEdge.hxx"
37 #include "SMDS_Downward.hxx"
38 #include "SMDS_SetIterator.hxx"
39
40 #include "SMESHDS_Group.hxx"
41 #include "SMESHDS_Mesh.hxx"
42
43 #include "SMESH_Algo.hxx"
44 #include "SMESH_ControlsDef.hxx"
45 #include "SMESH_Group.hxx"
46 #include "SMESH_MesherHelper.hxx"
47 #include "SMESH_OctreeNode.hxx"
48 #include "SMESH_subMesh.hxx"
49
50 #include <Basics_OCCTVersion.hxx>
51
52 #include "utilities.h"
53
54 #include <BRepAdaptor_Surface.hxx>
55 #include <BRepBuilderAPI_MakeEdge.hxx>
56 #include <BRepClass3d_SolidClassifier.hxx>
57 #include <BRep_Tool.hxx>
58 #include <ElCLib.hxx>
59 #include <Extrema_GenExtPS.hxx>
60 #include <Extrema_POnCurv.hxx>
61 #include <Extrema_POnSurf.hxx>
62 #include <GC_MakeSegment.hxx>
63 #include <Geom2d_Curve.hxx>
64 #include <GeomAPI_ExtremaCurveCurve.hxx>
65 #include <GeomAdaptor_Surface.hxx>
66 #include <Geom_Curve.hxx>
67 #include <Geom_Line.hxx>
68 #include <Geom_Surface.hxx>
69 #include <IntAna_IntConicQuad.hxx>
70 #include <IntAna_Quadric.hxx>
71 #include <Precision.hxx>
72 #include <TColStd_ListOfInteger.hxx>
73 #include <TopAbs_State.hxx>
74 #include <TopExp.hxx>
75 #include <TopExp_Explorer.hxx>
76 #include <TopTools_ListIteratorOfListOfShape.hxx>
77 #include <TopTools_ListOfShape.hxx>
78 #include <TopTools_SequenceOfShape.hxx>
79 #include <TopoDS.hxx>
80 #include <TopoDS_Face.hxx>
81 #include <gp.hxx>
82 #include <gp_Ax1.hxx>
83 #include <gp_Dir.hxx>
84 #include <gp_Lin.hxx>
85 #include <gp_Pln.hxx>
86 #include <gp_Trsf.hxx>
87 #include <gp_Vec.hxx>
88 #include <gp_XY.hxx>
89 #include <gp_XYZ.hxx>
90
91 #include <cmath>
92
93 #include <map>
94 #include <set>
95 #include <numeric>
96 #include <limits>
97 #include <algorithm>
98 #include <sstream>
99
100 #define cast2Node(elem) static_cast<const SMDS_MeshNode*>( elem )
101
102 using namespace std;
103 using namespace SMESH::Controls;
104
105 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshNode*> >    TElemOfNodeListMap;
106 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshElement*> > TElemOfElemListMap;
107
108 typedef SMDS_SetIterator< SMDS_pElement, TIDSortedElemSet::const_iterator> TSetIterator;
109
110 //=======================================================================
111 //function : SMESH_MeshEditor
112 //purpose  :
113 //=======================================================================
114
115 SMESH_MeshEditor::SMESH_MeshEditor( SMESH_Mesh* theMesh )
116   :myMesh( theMesh ) // theMesh may be NULL
117 {
118 }
119
120 //=======================================================================
121 /*!
122  * \brief Add element
123  */
124 //=======================================================================
125
126 SMDS_MeshElement*
127 SMESH_MeshEditor::AddElement(const vector<const SMDS_MeshNode*> & node,
128                              const SMDSAbs_ElementType            type,
129                              const bool                           isPoly,
130                              const int                            ID)
131 {
132   //MESSAGE("AddElement " <<node.size() << " " << type << " " << isPoly << " " << ID);
133   SMDS_MeshElement* e = 0;
134   int nbnode = node.size();
135   SMESHDS_Mesh* mesh = GetMeshDS();
136   switch ( type ) {
137   case SMDSAbs_Face:
138     if ( !isPoly ) {
139       if      (nbnode == 3) {
140         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], ID);
141         else           e = mesh->AddFace      (node[0], node[1], node[2] );
142       }
143       else if (nbnode == 4) {
144         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3], ID);
145         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3] );
146       }
147       else if (nbnode == 6) {
148         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
149                                                node[4], node[5], ID);
150         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3],
151                                                node[4], node[5] );
152       }
153       else if (nbnode == 8) {
154         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
155                                                node[4], node[5], node[6], node[7], ID);
156         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3],
157                                                node[4], node[5], node[6], node[7] );
158       }
159       else if (nbnode == 9) {
160         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
161                                                node[4], node[5], node[6], node[7], node[8], ID);
162         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3],
163                                                node[4], node[5], node[6], node[7], node[8] );
164       }
165     } else {
166       if ( ID >= 1 ) e = mesh->AddPolygonalFaceWithID(node, ID);
167       else           e = mesh->AddPolygonalFace      (node    );
168     }
169     break;
170
171   case SMDSAbs_Volume:
172     if ( !isPoly ) {
173       if      (nbnode == 4) {
174         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], ID);
175         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3] );
176       }
177       else if (nbnode == 5) {
178         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
179                                                  node[4], ID);
180         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
181                                                  node[4] );
182       }
183       else if (nbnode == 6) {
184         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
185                                                  node[4], node[5], ID);
186         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
187                                                  node[4], node[5] );
188       }
189       else if (nbnode == 8) {
190         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
191                                                  node[4], node[5], node[6], node[7], ID);
192         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
193                                                  node[4], node[5], node[6], node[7] );
194       }
195       else if (nbnode == 10) {
196         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
197                                                  node[4], node[5], node[6], node[7],
198                                                  node[8], node[9], ID);
199         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
200                                                  node[4], node[5], node[6], node[7],
201                                                  node[8], node[9] );
202       }
203       else if (nbnode == 12) {
204         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
205                                                  node[4], node[5], node[6], node[7],
206                                                  node[8], node[9], node[10], node[11], ID);
207         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
208                                                  node[4], node[5], node[6], node[7],
209                                                  node[8], node[9], node[10], node[11] );
210       }
211       else if (nbnode == 13) {
212         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
213                                                  node[4], node[5], node[6], node[7],
214                                                  node[8], node[9], node[10],node[11],
215                                                  node[12],ID);
216         else           e = mesh->AddVolume      (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] );
220       }
221       else if (nbnode == 15) {
222         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
223                                                  node[4], node[5], node[6], node[7],
224                                                  node[8], node[9], node[10],node[11],
225                                                  node[12],node[13],node[14],ID);
226         else           e = mesh->AddVolume      (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] );
230       }
231       else if (nbnode == 20) {
232         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
233                                                  node[4], node[5], node[6], node[7],
234                                                  node[8], node[9], node[10],node[11],
235                                                  node[12],node[13],node[14],node[15],
236                                                  node[16],node[17],node[18],node[19],ID);
237         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
238                                                  node[4], node[5], node[6], node[7],
239                                                  node[8], node[9], node[10],node[11],
240                                                  node[12],node[13],node[14],node[15],
241                                                  node[16],node[17],node[18],node[19] );
242       }
243       else if (nbnode == 27) {
244         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
245                                                  node[4], node[5], node[6], node[7],
246                                                  node[8], node[9], node[10],node[11],
247                                                  node[12],node[13],node[14],node[15],
248                                                  node[16],node[17],node[18],node[19],
249                                                  node[20],node[21],node[22],node[23],
250                                                  node[24],node[25],node[26], ID);
251         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
252                                                  node[4], node[5], node[6], node[7],
253                                                  node[8], node[9], node[10],node[11],
254                                                  node[12],node[13],node[14],node[15],
255                                                  node[16],node[17],node[18],node[19],
256                                                  node[20],node[21],node[22],node[23],
257                                                  node[24],node[25],node[26] );
258       }
259     }
260     break;
261
262   case SMDSAbs_Edge:
263     if ( nbnode == 2 ) {
264       if ( ID >= 1 ) e = mesh->AddEdgeWithID(node[0], node[1], ID);
265       else           e = mesh->AddEdge      (node[0], node[1] );
266     }
267     else if ( nbnode == 3 ) {
268       if ( ID >= 1 ) e = mesh->AddEdgeWithID(node[0], node[1], node[2], ID);
269       else           e = mesh->AddEdge      (node[0], node[1], node[2] );
270     }
271     break;
272
273   case SMDSAbs_0DElement:
274     if ( nbnode == 1 ) {
275       if ( ID >= 1 ) e = mesh->Add0DElementWithID(node[0], ID);
276       else           e = mesh->Add0DElement      (node[0] );
277     }
278     break;
279
280   case SMDSAbs_Node:
281     if ( ID >= 1 ) e = mesh->AddNodeWithID(node[0]->X(), node[0]->Y(), node[0]->Z(), ID);
282     else           e = mesh->AddNode      (node[0]->X(), node[0]->Y(), node[0]->Z());
283     break;
284
285   default:;
286   }
287   if ( e ) myLastCreatedElems.Append( e );
288   return e;
289 }
290
291 //=======================================================================
292 /*!
293  * \brief Add element
294  */
295 //=======================================================================
296
297 SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector<int> &       nodeIDs,
298                                                const SMDSAbs_ElementType type,
299                                                const bool                isPoly,
300                                                const int                 ID)
301 {
302   vector<const SMDS_MeshNode*> nodes;
303   nodes.reserve( nodeIDs.size() );
304   vector<int>::const_iterator id = nodeIDs.begin();
305   while ( id != nodeIDs.end() ) {
306     if ( const SMDS_MeshNode* node = GetMeshDS()->FindNode( *id++ ))
307       nodes.push_back( node );
308     else
309       return 0;
310   }
311   return AddElement( nodes, type, isPoly, ID );
312 }
313
314 //=======================================================================
315 //function : Remove
316 //purpose  : Remove a node or an element.
317 //           Modify a compute state of sub-meshes which become empty
318 //=======================================================================
319
320 int SMESH_MeshEditor::Remove (const list< int >& theIDs,
321                               const bool         isNodes )
322 {
323   myLastCreatedElems.Clear();
324   myLastCreatedNodes.Clear();
325
326   SMESHDS_Mesh* aMesh = GetMeshDS();
327   set< SMESH_subMesh *> smmap;
328
329   int removed = 0;
330   list<int>::const_iterator it = theIDs.begin();
331   for ( ; it != theIDs.end(); it++ ) {
332     const SMDS_MeshElement * elem;
333     if ( isNodes )
334       elem = aMesh->FindNode( *it );
335     else
336       elem = aMesh->FindElement( *it );
337     if ( !elem )
338       continue;
339
340     // Notify VERTEX sub-meshes about modification
341     if ( isNodes ) {
342       const SMDS_MeshNode* node = cast2Node( elem );
343       if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX )
344         if ( int aShapeID = node->getshapeId() )
345           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
346             smmap.insert( sm );
347     }
348     // Find sub-meshes to notify about modification
349     //     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
350     //     while ( nodeIt->more() ) {
351     //       const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
352     //       const SMDS_PositionPtr& aPosition = node->GetPosition();
353     //       if ( aPosition.get() ) {
354     //         if ( int aShapeID = aPosition->GetShapeId() ) {
355     //           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
356     //             smmap.insert( sm );
357     //         }
358     //       }
359     //     }
360
361     // Do remove
362     if ( isNodes )
363       aMesh->RemoveNode( static_cast< const SMDS_MeshNode* >( elem ));
364     else
365       aMesh->RemoveElement( elem );
366     removed++;
367   }
368
369   // Notify sub-meshes about modification
370   if ( !smmap.empty() ) {
371     set< SMESH_subMesh *>::iterator smIt;
372     for ( smIt = smmap.begin(); smIt != smmap.end(); smIt++ )
373       (*smIt)->ComputeStateEngine( SMESH_subMesh::MESH_ENTITY_REMOVED );
374   }
375
376   //   // Check if the whole mesh becomes empty
377   //   if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( 1 ) )
378   //     sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
379
380   return removed;
381 }
382
383 //=======================================================================
384 //function : FindShape
385 //purpose  : Return an index of the shape theElem is on
386 //           or zero if a shape not found
387 //=======================================================================
388
389 int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem)
390 {
391   myLastCreatedElems.Clear();
392   myLastCreatedNodes.Clear();
393
394   SMESHDS_Mesh * aMesh = GetMeshDS();
395   if ( aMesh->ShapeToMesh().IsNull() )
396     return 0;
397
398   int aShapeID = theElem->getshapeId();
399   if ( aShapeID < 1 )
400     return 0;
401
402   if ( SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID ))
403     if ( sm->Contains( theElem ))
404       return aShapeID;
405
406   if ( theElem->GetType() == SMDSAbs_Node ) {
407     MESSAGE( ":( Error: invalid myShapeId of node " << theElem->GetID() );
408   }
409   else {
410     MESSAGE( ":( Error: invalid myShapeId of element " << theElem->GetID() );
411   }
412
413   TopoDS_Shape aShape; // the shape a node of theElem is on
414   if ( theElem->GetType() != SMDSAbs_Node )
415   {
416     SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
417     while ( nodeIt->more() ) {
418       const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
419       if ((aShapeID = node->getshapeId()) > 0) {
420         if ( SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID ) ) {
421           if ( sm->Contains( theElem ))
422             return aShapeID;
423           if ( aShape.IsNull() )
424             aShape = aMesh->IndexToShape( aShapeID );
425         }
426       }
427     }
428   }
429
430   // None of nodes is on a proper shape,
431   // find the shape among ancestors of aShape on which a node is
432   if ( !aShape.IsNull() ) {
433     TopTools_ListIteratorOfListOfShape ancIt( GetMesh()->GetAncestors( aShape ));
434     for ( ; ancIt.More(); ancIt.Next() ) {
435       SMESHDS_SubMesh * sm = aMesh->MeshElements( ancIt.Value() );
436       if ( sm && sm->Contains( theElem ))
437         return aMesh->ShapeToIndex( ancIt.Value() );
438     }
439   }
440   else
441   {
442     const map<int,SMESHDS_SubMesh*>& id2sm = GetMeshDS()->SubMeshes();
443     map<int,SMESHDS_SubMesh*>::const_iterator id_sm = id2sm.begin();
444     for ( ; id_sm != id2sm.end(); ++id_sm )
445       if ( id_sm->second->Contains( theElem ))
446         return id_sm->first;
447   }
448
449   //MESSAGE ("::FindShape() - SHAPE NOT FOUND")
450   return 0;
451 }
452
453 //=======================================================================
454 //function : IsMedium
455 //purpose  :
456 //=======================================================================
457
458 bool SMESH_MeshEditor::IsMedium(const SMDS_MeshNode*      node,
459                                 const SMDSAbs_ElementType typeToCheck)
460 {
461   bool isMedium = false;
462   SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(typeToCheck);
463   while (it->more() && !isMedium ) {
464     const SMDS_MeshElement* elem = it->next();
465     isMedium = elem->IsMediumNode(node);
466   }
467   return isMedium;
468 }
469
470 //=======================================================================
471 //function : ShiftNodesQuadTria
472 //purpose  : auxilary
473 //           Shift nodes in the array corresponded to quadratic triangle
474 //           example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
475 //=======================================================================
476 static void ShiftNodesQuadTria(const SMDS_MeshNode* aNodes[])
477 {
478   const SMDS_MeshNode* nd1 = aNodes[0];
479   aNodes[0] = aNodes[1];
480   aNodes[1] = aNodes[2];
481   aNodes[2] = nd1;
482   const SMDS_MeshNode* nd2 = aNodes[3];
483   aNodes[3] = aNodes[4];
484   aNodes[4] = aNodes[5];
485   aNodes[5] = nd2;
486 }
487
488 //=======================================================================
489 //function : edgeConnectivity
490 //purpose  : auxilary 
491 //           return number of the edges connected with the theNode.
492 //           if theEdges has connections with the other type of the
493 //           elements, return -1 
494 //=======================================================================
495 static int nbEdgeConnectivity(const SMDS_MeshNode* theNode)
496 {
497   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator();
498   int nb=0;
499   while(elemIt->more()) {
500     elemIt->next();
501     nb++;
502   }
503   return nb;
504 }
505
506
507 //=======================================================================
508 //function : GetNodesFromTwoTria
509 //purpose  : auxilary
510 //           Shift nodes in the array corresponded to quadratic triangle
511 //           example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
512 //=======================================================================
513 static bool GetNodesFromTwoTria(const SMDS_MeshElement * theTria1,
514                                 const SMDS_MeshElement * theTria2,
515                                 const SMDS_MeshNode* N1[],
516                                 const SMDS_MeshNode* N2[])
517 {
518   SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
519   int i=0;
520   while(i<6) {
521     N1[i] = static_cast<const SMDS_MeshNode*>( it->next() );
522     i++;
523   }
524   if(it->more()) return false;
525   it = theTria2->nodesIterator();
526   i=0;
527   while(i<6) {
528     N2[i] = static_cast<const SMDS_MeshNode*>( it->next() );
529     i++;
530   }
531   if(it->more()) return false;
532
533   int sames[3] = {-1,-1,-1};
534   int nbsames = 0;
535   int j;
536   for(i=0; i<3; i++) {
537     for(j=0; j<3; j++) {
538       if(N1[i]==N2[j]) {
539         sames[i] = j;
540         nbsames++;
541         break;
542       }
543     }
544   }
545   if(nbsames!=2) return false;
546   if(sames[0]>-1) {
547     ShiftNodesQuadTria(N1);
548     if(sames[1]>-1) {
549       ShiftNodesQuadTria(N1);
550     }
551   }
552   i = sames[0] + sames[1] + sames[2];
553   for(; i<2; i++) {
554     ShiftNodesQuadTria(N2);
555   }
556   // now we receive following N1 and N2 (using numeration as above image)
557   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
558   // i.e. first nodes from both arrays determ new diagonal
559   return true;
560 }
561
562 //=======================================================================
563 //function : InverseDiag
564 //purpose  : Replace two neighbour triangles with ones built on the same 4 nodes
565 //           but having other common link.
566 //           Return False if args are improper
567 //=======================================================================
568
569 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1,
570                                     const SMDS_MeshElement * theTria2 )
571 {
572   MESSAGE("InverseDiag");
573   myLastCreatedElems.Clear();
574   myLastCreatedNodes.Clear();
575
576   if (!theTria1 || !theTria2)
577     return false;
578
579   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( theTria1 );
580   if (!F1) return false;
581   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( theTria2 );
582   if (!F2) return false;
583   if ((theTria1->GetEntityType() == SMDSEntity_Triangle) &&
584       (theTria2->GetEntityType() == SMDSEntity_Triangle)) {
585
586     //  1 +--+ A  theTria1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
587     //    | /|    theTria2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
588     //    |/ |                                         | \|
589     //  B +--+ 2                                     B +--+ 2
590
591     // put nodes in array and find out indices of the same ones
592     const SMDS_MeshNode* aNodes [6];
593     int sameInd [] = { 0, 0, 0, 0, 0, 0 };
594     int i = 0;
595     SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
596     while ( it->more() ) {
597       aNodes[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
598
599       if ( i > 2 ) // theTria2
600         // find same node of theTria1
601         for ( int j = 0; j < 3; j++ )
602           if ( aNodes[ i ] == aNodes[ j ]) {
603             sameInd[ j ] = i;
604             sameInd[ i ] = j;
605             break;
606           }
607       // next
608       i++;
609       if ( i == 3 ) {
610         if ( it->more() )
611           return false; // theTria1 is not a triangle
612         it = theTria2->nodesIterator();
613       }
614       if ( i == 6 && it->more() )
615         return false; // theTria2 is not a triangle
616     }
617
618     // find indices of 1,2 and of A,B in theTria1
619     int iA = 0, iB = 0, i1 = 0, i2 = 0;
620     for ( i = 0; i < 6; i++ ) {
621       if ( sameInd [ i ] == 0 ) {
622         if ( i < 3 ) i1 = i;
623         else         i2 = i;
624       }
625       else if (i < 3) {
626         if ( iA ) iB = i;
627         else      iA = i;
628       }
629     }
630     // nodes 1 and 2 should not be the same
631     if ( aNodes[ i1 ] == aNodes[ i2 ] )
632       return false;
633
634     // theTria1: A->2
635     aNodes[ iA ] = aNodes[ i2 ];
636     // theTria2: B->1
637     aNodes[ sameInd[ iB ]] = aNodes[ i1 ];
638
639     GetMeshDS()->ChangeElementNodes( theTria1, aNodes, 3 );
640     GetMeshDS()->ChangeElementNodes( theTria2, &aNodes[ 3 ], 3 );
641
642     return true;
643
644   } // end if(F1 && F2)
645
646   // check case of quadratic faces
647   if (theTria1->GetEntityType() != SMDSEntity_Quad_Triangle)
648     return false;
649   if (theTria2->GetEntityType() != SMDSEntity_Quad_Triangle)
650     return false;
651
652   //       5
653   //  1 +--+--+ 2  theTria1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
654   //    |    /|    theTria2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
655   //    |   / |
656   //  7 +  +  + 6
657   //    | /9  |
658   //    |/    |
659   //  4 +--+--+ 3
660   //       8
661
662   const SMDS_MeshNode* N1 [6];
663   const SMDS_MeshNode* N2 [6];
664   if(!GetNodesFromTwoTria(theTria1,theTria2,N1,N2))
665     return false;
666   // now we receive following N1 and N2 (using numeration as above image)
667   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
668   // i.e. first nodes from both arrays determ new diagonal
669
670   const SMDS_MeshNode* N1new [6];
671   const SMDS_MeshNode* N2new [6];
672   N1new[0] = N1[0];
673   N1new[1] = N2[0];
674   N1new[2] = N2[1];
675   N1new[3] = N1[4];
676   N1new[4] = N2[3];
677   N1new[5] = N1[5];
678   N2new[0] = N1[0];
679   N2new[1] = N1[1];
680   N2new[2] = N2[0];
681   N2new[3] = N1[3];
682   N2new[4] = N2[5];
683   N2new[5] = N1[4];
684   // replaces nodes in faces
685   GetMeshDS()->ChangeElementNodes( theTria1, N1new, 6 );
686   GetMeshDS()->ChangeElementNodes( theTria2, N2new, 6 );
687
688   return true;
689 }
690
691 //=======================================================================
692 //function : findTriangles
693 //purpose  : find triangles sharing theNode1-theNode2 link
694 //=======================================================================
695
696 static bool findTriangles(const SMDS_MeshNode *    theNode1,
697                           const SMDS_MeshNode *    theNode2,
698                           const SMDS_MeshElement*& theTria1,
699                           const SMDS_MeshElement*& theTria2)
700 {
701   if ( !theNode1 || !theNode2 ) return false;
702
703   theTria1 = theTria2 = 0;
704
705   set< const SMDS_MeshElement* > emap;
706   SMDS_ElemIteratorPtr it = theNode1->GetInverseElementIterator(SMDSAbs_Face);
707   while (it->more()) {
708     const SMDS_MeshElement* elem = it->next();
709     if ( elem->NbNodes() == 3 )
710       emap.insert( elem );
711   }
712   it = theNode2->GetInverseElementIterator(SMDSAbs_Face);
713   while (it->more()) {
714     const SMDS_MeshElement* elem = it->next();
715     if ( emap.find( elem ) != emap.end() ) {
716       if ( theTria1 ) {
717         // theTria1 must be element with minimum ID
718         if( theTria1->GetID() < elem->GetID() ) {
719           theTria2 = elem;
720         }
721         else {
722           theTria2 = theTria1;
723           theTria1 = elem;
724         }
725         break;
726       }
727       else {
728         theTria1 = elem;
729       }
730     }
731   }
732   return ( theTria1 && theTria2 );
733 }
734
735 //=======================================================================
736 //function : InverseDiag
737 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
738 //           with ones built on the same 4 nodes but having other common link.
739 //           Return false if proper faces not found
740 //=======================================================================
741
742 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshNode * theNode1,
743                                     const SMDS_MeshNode * theNode2)
744 {
745   myLastCreatedElems.Clear();
746   myLastCreatedNodes.Clear();
747
748   MESSAGE( "::InverseDiag()" );
749
750   const SMDS_MeshElement *tr1, *tr2;
751   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
752     return false;
753
754   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
755   if (!F1) return false;
756   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
757   if (!F2) return false;
758   if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
759       (tr2->GetEntityType() == SMDSEntity_Triangle)) {
760
761     //  1 +--+ A  tr1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
762     //    | /|    tr2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
763     //    |/ |                                    | \|
764     //  B +--+ 2                                B +--+ 2
765
766     // put nodes in array
767     // and find indices of 1,2 and of A in tr1 and of B in tr2
768     int i, iA1 = 0, i1 = 0;
769     const SMDS_MeshNode* aNodes1 [3];
770     SMDS_ElemIteratorPtr it;
771     for (i = 0, it = tr1->nodesIterator(); it->more(); i++ ) {
772       aNodes1[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
773       if ( aNodes1[ i ] == theNode1 )
774         iA1 = i; // node A in tr1
775       else if ( aNodes1[ i ] != theNode2 )
776         i1 = i;  // node 1
777     }
778     int iB2 = 0, i2 = 0;
779     const SMDS_MeshNode* aNodes2 [3];
780     for (i = 0, it = tr2->nodesIterator(); it->more(); i++ ) {
781       aNodes2[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
782       if ( aNodes2[ i ] == theNode2 )
783         iB2 = i; // node B in tr2
784       else if ( aNodes2[ i ] != theNode1 )
785         i2 = i;  // node 2
786     }
787
788     // nodes 1 and 2 should not be the same
789     if ( aNodes1[ i1 ] == aNodes2[ i2 ] )
790       return false;
791
792     // tr1: A->2
793     aNodes1[ iA1 ] = aNodes2[ i2 ];
794     // tr2: B->1
795     aNodes2[ iB2 ] = aNodes1[ i1 ];
796
797     GetMeshDS()->ChangeElementNodes( tr1, aNodes1, 3 );
798     GetMeshDS()->ChangeElementNodes( tr2, aNodes2, 3 );
799
800     return true;
801   }
802
803   // check case of quadratic faces
804   return InverseDiag(tr1,tr2);
805 }
806
807 //=======================================================================
808 //function : getQuadrangleNodes
809 //purpose  : fill theQuadNodes - nodes of a quadrangle resulting from
810 //           fusion of triangles tr1 and tr2 having shared link on
811 //           theNode1 and theNode2
812 //=======================================================================
813
814 bool getQuadrangleNodes(const SMDS_MeshNode *    theQuadNodes [],
815                         const SMDS_MeshNode *    theNode1,
816                         const SMDS_MeshNode *    theNode2,
817                         const SMDS_MeshElement * tr1,
818                         const SMDS_MeshElement * tr2 )
819 {
820   if( tr1->NbNodes() != tr2->NbNodes() )
821     return false;
822   // find the 4-th node to insert into tr1
823   const SMDS_MeshNode* n4 = 0;
824   SMDS_ElemIteratorPtr it = tr2->nodesIterator();
825   int i=0;
826   while ( !n4 && i<3 ) {
827     const SMDS_MeshNode * n = cast2Node( it->next() );
828     i++;
829     bool isDiag = ( n == theNode1 || n == theNode2 );
830     if ( !isDiag )
831       n4 = n;
832   }
833   // Make an array of nodes to be in a quadrangle
834   int iNode = 0, iFirstDiag = -1;
835   it = tr1->nodesIterator();
836   i=0;
837   while ( i<3 ) {
838     const SMDS_MeshNode * n = cast2Node( it->next() );
839     i++;
840     bool isDiag = ( n == theNode1 || n == theNode2 );
841     if ( isDiag ) {
842       if ( iFirstDiag < 0 )
843         iFirstDiag = iNode;
844       else if ( iNode - iFirstDiag == 1 )
845         theQuadNodes[ iNode++ ] = n4; // insert the 4-th node between diagonal nodes
846     }
847     else if ( n == n4 ) {
848       return false; // tr1 and tr2 should not have all the same nodes
849     }
850     theQuadNodes[ iNode++ ] = n;
851   }
852   if ( iNode == 3 ) // diagonal nodes have 0 and 2 indices
853     theQuadNodes[ iNode ] = n4;
854
855   return true;
856 }
857
858 //=======================================================================
859 //function : DeleteDiag
860 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
861 //           with a quadrangle built on the same 4 nodes.
862 //           Return false if proper faces not found
863 //=======================================================================
864
865 bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1,
866                                    const SMDS_MeshNode * theNode2)
867 {
868   myLastCreatedElems.Clear();
869   myLastCreatedNodes.Clear();
870
871   MESSAGE( "::DeleteDiag()" );
872
873   const SMDS_MeshElement *tr1, *tr2;
874   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
875     return false;
876
877   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
878   if (!F1) return false;
879   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
880   if (!F2) return false;
881   SMESHDS_Mesh * aMesh = GetMeshDS();
882
883   if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
884       (tr2->GetEntityType() == SMDSEntity_Triangle)) {
885
886     const SMDS_MeshNode* aNodes [ 4 ];
887     if ( ! getQuadrangleNodes( aNodes, theNode1, theNode2, tr1, tr2 ))
888       return false;
889
890     const SMDS_MeshElement* newElem = 0;
891     newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3] );
892     myLastCreatedElems.Append(newElem);
893     AddToSameGroups( newElem, tr1, aMesh );
894     int aShapeId = tr1->getshapeId();
895     if ( aShapeId )
896       {
897         aMesh->SetMeshElementOnShape( newElem, aShapeId );
898       }
899     aMesh->RemoveElement( tr1 );
900     aMesh->RemoveElement( tr2 );
901
902     return true;
903   }
904
905   // check case of quadratic faces
906   if (tr1->GetEntityType() != SMDSEntity_Quad_Triangle)
907     return false;
908   if (tr2->GetEntityType() != SMDSEntity_Quad_Triangle)
909     return false;
910
911   //       5
912   //  1 +--+--+ 2  tr1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
913   //    |    /|    tr2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
914   //    |   / |
915   //  7 +  +  + 6
916   //    | /9  |
917   //    |/    |
918   //  4 +--+--+ 3
919   //       8
920
921   const SMDS_MeshNode* N1 [6];
922   const SMDS_MeshNode* N2 [6];
923   if(!GetNodesFromTwoTria(tr1,tr2,N1,N2))
924     return false;
925   // now we receive following N1 and N2 (using numeration as above image)
926   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
927   // i.e. first nodes from both arrays determ new diagonal
928
929   const SMDS_MeshNode* aNodes[8];
930   aNodes[0] = N1[0];
931   aNodes[1] = N1[1];
932   aNodes[2] = N2[0];
933   aNodes[3] = N2[1];
934   aNodes[4] = N1[3];
935   aNodes[5] = N2[5];
936   aNodes[6] = N2[3];
937   aNodes[7] = N1[5];
938
939   const SMDS_MeshElement* newElem = 0;
940   newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3],
941                             aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
942   myLastCreatedElems.Append(newElem);
943   AddToSameGroups( newElem, tr1, aMesh );
944   int aShapeId = tr1->getshapeId();
945   if ( aShapeId )
946     {
947       aMesh->SetMeshElementOnShape( newElem, aShapeId );
948     }
949   aMesh->RemoveElement( tr1 );
950   aMesh->RemoveElement( tr2 );
951
952   // remove middle node (9)
953   GetMeshDS()->RemoveNode( N1[4] );
954
955   return true;
956 }
957
958 //=======================================================================
959 //function : Reorient
960 //purpose  : Reverse theElement orientation
961 //=======================================================================
962
963 bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem)
964 {
965   MESSAGE("Reorient");
966   myLastCreatedElems.Clear();
967   myLastCreatedNodes.Clear();
968
969   if (!theElem)
970     return false;
971   SMDS_ElemIteratorPtr it = theElem->nodesIterator();
972   if ( !it || !it->more() )
973     return false;
974
975   switch ( theElem->GetType() ) {
976
977   case SMDSAbs_Edge:
978   case SMDSAbs_Face: {
979     if(!theElem->IsQuadratic()) {
980       int i = theElem->NbNodes();
981       vector<const SMDS_MeshNode*> aNodes( i );
982       while ( it->more() )
983         aNodes[ --i ]= static_cast<const SMDS_MeshNode*>( it->next() );
984       return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], theElem->NbNodes() );
985     }
986     else {
987       // quadratic elements
988       if(theElem->GetType()==SMDSAbs_Edge) {
989         vector<const SMDS_MeshNode*> aNodes(3);
990         aNodes[1]= static_cast<const SMDS_MeshNode*>( it->next() );
991         aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
992         aNodes[2]= static_cast<const SMDS_MeshNode*>( it->next() );
993         return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], 3 );
994       }
995       else {
996         int nbn = theElem->NbNodes();
997         vector<const SMDS_MeshNode*> aNodes(nbn);
998         aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
999         int i=1;
1000         for(; i<nbn/2; i++) {
1001           aNodes[nbn/2-i]= static_cast<const SMDS_MeshNode*>( it->next() );
1002         }
1003         for(i=0; i<nbn/2; i++) {
1004           aNodes[nbn-i-1]= static_cast<const SMDS_MeshNode*>( it->next() );
1005         }
1006         return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], nbn );
1007       }
1008     }
1009   }
1010   case SMDSAbs_Volume: {
1011     if (theElem->IsPoly()) {
1012       // TODO reorient vtk polyhedron
1013       MESSAGE("reorient vtk polyhedron ?");
1014       const SMDS_VtkVolume* aPolyedre =
1015         dynamic_cast<const SMDS_VtkVolume*>( theElem );
1016       if (!aPolyedre) {
1017         MESSAGE("Warning: bad volumic element");
1018         return false;
1019       }
1020
1021       int nbFaces = aPolyedre->NbFaces();
1022       vector<const SMDS_MeshNode *> poly_nodes;
1023       vector<int> quantities (nbFaces);
1024
1025       // reverse each face of the polyedre
1026       for (int iface = 1; iface <= nbFaces; iface++) {
1027         int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
1028         quantities[iface - 1] = nbFaceNodes;
1029
1030         for (inode = nbFaceNodes; inode >= 1; inode--) {
1031           const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
1032           poly_nodes.push_back(curNode);
1033         }
1034       }
1035
1036       return GetMeshDS()->ChangePolyhedronNodes( theElem, poly_nodes, quantities );
1037
1038     }
1039     else {
1040       SMDS_VolumeTool vTool;
1041       if ( !vTool.Set( theElem ))
1042         return false;
1043       vTool.Inverse();
1044       MESSAGE("ChangeElementNodes reorient: check vTool.Inverse");
1045       return GetMeshDS()->ChangeElementNodes( theElem, vTool.GetNodes(), vTool.NbNodes() );
1046     }
1047   }
1048   default:;
1049   }
1050
1051   return false;
1052 }
1053
1054 //=======================================================================
1055 //function : getBadRate
1056 //purpose  :
1057 //=======================================================================
1058
1059 static double getBadRate (const SMDS_MeshElement*               theElem,
1060                           SMESH::Controls::NumericalFunctorPtr& theCrit)
1061 {
1062   SMESH::Controls::TSequenceOfXYZ P;
1063   if ( !theElem || !theCrit->GetPoints( theElem, P ))
1064     return 1e100;
1065   return theCrit->GetBadRate( theCrit->GetValue( P ), theElem->NbNodes() );
1066   //return theCrit->GetBadRate( theCrit->GetValue( theElem->GetID() ), theElem->NbNodes() );
1067 }
1068
1069 //=======================================================================
1070 //function : QuadToTri
1071 //purpose  : Cut quadrangles into triangles.
1072 //           theCrit is used to select a diagonal to cut
1073 //=======================================================================
1074
1075 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet &                   theElems,
1076                                   SMESH::Controls::NumericalFunctorPtr theCrit)
1077 {
1078   myLastCreatedElems.Clear();
1079   myLastCreatedNodes.Clear();
1080
1081   MESSAGE( "::QuadToTri()" );
1082
1083   if ( !theCrit.get() )
1084     return false;
1085
1086   SMESHDS_Mesh * aMesh = GetMeshDS();
1087
1088   Handle(Geom_Surface) surface;
1089   SMESH_MesherHelper   helper( *GetMesh() );
1090
1091   TIDSortedElemSet::iterator itElem;
1092   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1093     const SMDS_MeshElement* elem = *itElem;
1094     if ( !elem || elem->GetType() != SMDSAbs_Face )
1095       continue;
1096     if ( elem->NbCornerNodes() != 4 )
1097       continue;
1098
1099     // retrieve element nodes
1100     vector< const SMDS_MeshNode* > aNodes( elem->begin_nodes(), elem->end_nodes() );
1101
1102     // compare two sets of possible triangles
1103     double aBadRate1, aBadRate2; // to what extent a set is bad
1104     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1105     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1106     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1107
1108     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1109     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1110     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1111
1112     int aShapeId = FindShape( elem );
1113     const SMDS_MeshElement* newElem1 = 0;
1114     const SMDS_MeshElement* newElem2 = 0;
1115
1116     if( !elem->IsQuadratic() ) {
1117
1118       // split liner quadrangle
1119
1120       if ( aBadRate1 <= aBadRate2 ) {
1121         // tr1 + tr2 is better
1122         newElem1 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1123         newElem2 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
1124       }
1125       else {
1126         // tr3 + tr4 is better
1127         newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1128         newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
1129       }
1130     }
1131     else {
1132
1133       // split quadratic quadrangle
1134
1135       // get surface elem is on
1136       if ( aShapeId != helper.GetSubShapeID() ) {
1137         surface.Nullify();
1138         TopoDS_Shape shape;
1139         if ( aShapeId > 0 )
1140           shape = aMesh->IndexToShape( aShapeId );
1141         if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1142           TopoDS_Face face = TopoDS::Face( shape );
1143           surface = BRep_Tool::Surface( face );
1144           if ( !surface.IsNull() )
1145             helper.SetSubShape( shape );
1146         }
1147       }
1148       // find middle point for (0,1,2,3)
1149       // and create a node in this point;
1150       const SMDS_MeshNode* newN = 0;
1151       if ( aNodes.size() == 9 )
1152       {
1153         // SMDSEntity_BiQuad_Quadrangle
1154         newN = aNodes.back();
1155       }
1156       else
1157       {
1158         gp_XYZ p( 0,0,0 );
1159         if ( surface.IsNull() )
1160         {
1161           for ( int i = 0; i < 4; i++ )
1162             p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1163           p /= 4;
1164         }
1165         else
1166         {
1167           const SMDS_MeshNode* inFaceNode = 0;
1168           if ( helper.GetNodeUVneedInFaceNode() )
1169             for ( size_t i = 0; i < aNodes.size() && !inFaceNode; ++i )
1170               if ( aNodes[ i ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1171                 inFaceNode = aNodes[ i ];
1172
1173           TopoDS_Face face = TopoDS::Face( helper.GetSubShape() );
1174           gp_XY uv( 0,0 );
1175           for ( int i = 0; i < 4; i++ )
1176             uv += helper.GetNodeUV( face, aNodes[i], inFaceNode );
1177           uv /= 4.;
1178           p = surface->Value( uv.X(), uv.Y() ).XYZ();
1179         }
1180         newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1181         myLastCreatedNodes.Append(newN);
1182       }
1183       // create a new element
1184       if ( aBadRate1 <= aBadRate2 ) {
1185         newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1186                                   aNodes[6], aNodes[7], newN );
1187         newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
1188                                   newN,      aNodes[4], aNodes[5] );
1189       }
1190       else {
1191         newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1192                                   aNodes[7], aNodes[4], newN );
1193         newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
1194                                   newN,      aNodes[5], aNodes[6] );
1195       }
1196     } // quadratic case
1197
1198     // care of a new element
1199
1200     myLastCreatedElems.Append(newElem1);
1201     myLastCreatedElems.Append(newElem2);
1202     AddToSameGroups( newElem1, elem, aMesh );
1203     AddToSameGroups( newElem2, elem, aMesh );
1204
1205     // put a new triangle on the same shape
1206     if ( aShapeId )
1207       {
1208         aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1209         aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1210       }
1211     aMesh->RemoveElement( elem );
1212   }
1213   return true;
1214 }
1215
1216 //=======================================================================
1217 //function : BestSplit
1218 //purpose  : Find better diagonal for cutting.
1219 //=======================================================================
1220
1221 int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement*              theQuad,
1222                                  SMESH::Controls::NumericalFunctorPtr theCrit)
1223 {
1224   myLastCreatedElems.Clear();
1225   myLastCreatedNodes.Clear();
1226
1227   if (!theCrit.get())
1228     return -1;
1229
1230   if (!theQuad || theQuad->GetType() != SMDSAbs_Face )
1231     return -1;
1232
1233   if( theQuad->NbNodes()==4 ||
1234       (theQuad->NbNodes()==8 && theQuad->IsQuadratic()) ) {
1235
1236     // retrieve element nodes
1237     const SMDS_MeshNode* aNodes [4];
1238     SMDS_ElemIteratorPtr itN = theQuad->nodesIterator();
1239     int i = 0;
1240     //while (itN->more())
1241     while (i<4) {
1242       aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1243     }
1244     // compare two sets of possible triangles
1245     double aBadRate1, aBadRate2; // to what extent a set is bad
1246     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1247     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1248     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1249
1250     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1251     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1252     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1253
1254     if (aBadRate1 <= aBadRate2) // tr1 + tr2 is better
1255       return 1; // diagonal 1-3
1256
1257     return 2; // diagonal 2-4
1258   }
1259   return -1;
1260 }
1261
1262 namespace
1263 {
1264   // Methods of splitting volumes into tetra
1265
1266   const int theHexTo5_1[5*4+1] =
1267     {
1268       0, 1, 2, 5,    0, 4, 5, 7,     0, 2, 3, 7,    2, 5, 6, 7,     0, 5, 2, 7,   -1
1269     };
1270   const int theHexTo5_2[5*4+1] =
1271     {
1272       1, 2, 3, 6,    1, 4, 5, 6,     0, 1, 3, 4,    3, 4, 6, 7,     1, 3, 4, 6,   -1
1273     };
1274   const int* theHexTo5[2] = { theHexTo5_1, theHexTo5_2 };
1275
1276   const int theHexTo6_1[6*4+1] =
1277     {
1278       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
1279     };
1280   const int theHexTo6_2[6*4+1] =
1281     {
1282       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
1283     };
1284   const int theHexTo6_3[6*4+1] =
1285     {
1286       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
1287     };
1288   const int theHexTo6_4[6*4+1] =
1289     {
1290       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
1291     };
1292   const int* theHexTo6[4] = { theHexTo6_1, theHexTo6_2, theHexTo6_3, theHexTo6_4 };
1293
1294   const int thePyraTo2_1[2*4+1] =
1295     {
1296       0, 1, 2, 4,    0, 2, 3, 4,   -1
1297     };
1298   const int thePyraTo2_2[2*4+1] =
1299     {
1300       1, 2, 3, 4,    1, 3, 0, 4,   -1
1301     };
1302   const int* thePyraTo2[2] = { thePyraTo2_1, thePyraTo2_2 };
1303
1304   const int thePentaTo3_1[3*4+1] =
1305     {
1306       0, 1, 2, 3,    1, 3, 4, 2,     2, 3, 4, 5,    -1
1307     };
1308   const int thePentaTo3_2[3*4+1] =
1309     {
1310       1, 2, 0, 4,    2, 4, 5, 0,     0, 4, 5, 3,    -1
1311     };
1312   const int thePentaTo3_3[3*4+1] =
1313     {
1314       2, 0, 1, 5,    0, 5, 3, 1,     1, 5, 3, 4,    -1
1315     };
1316   const int thePentaTo3_4[3*4+1] =
1317     {
1318       0, 1, 2, 3,    1, 3, 4, 5,     2, 3, 1, 5,    -1
1319     };
1320   const int thePentaTo3_5[3*4+1] =
1321     {
1322       1, 2, 0, 4,    2, 4, 5, 3,     0, 4, 2, 3,    -1
1323     };
1324   const int thePentaTo3_6[3*4+1] =
1325     {
1326       2, 0, 1, 5,    0, 5, 3, 4,     1, 5, 0, 4,    -1
1327     };
1328   const int* thePentaTo3[6] = { thePentaTo3_1, thePentaTo3_2, thePentaTo3_3,
1329                                 thePentaTo3_4, thePentaTo3_5, thePentaTo3_6 };
1330
1331   struct TTriangleFacet //!< stores indices of three nodes of tetra facet
1332   {
1333     int _n1, _n2, _n3;
1334     TTriangleFacet(int n1, int n2, int n3): _n1(n1), _n2(n2), _n3(n3) {}
1335     bool contains(int n) const { return ( n == _n1 || n == _n2 || n == _n3 ); }
1336     bool hasAdjacentTetra( const SMDS_MeshElement* elem ) const;
1337   };
1338   struct TSplitMethod
1339   {
1340     int        _nbTetra;
1341     const int* _connectivity; //!< foursomes of tetra connectivy finished by -1
1342     bool       _baryNode;     //!< additional node is to be created at cell barycenter
1343     bool       _ownConn;      //!< to delete _connectivity in destructor
1344     map<int, const SMDS_MeshNode*> _faceBaryNode; //!< map face index to node at BC of face
1345
1346     TSplitMethod( int nbTet=0, const int* conn=0, bool addNode=false)
1347       : _nbTetra(nbTet), _connectivity(conn), _baryNode(addNode), _ownConn(false) {}
1348     ~TSplitMethod() { if ( _ownConn ) delete [] _connectivity; _connectivity = 0; }
1349     bool hasFacet( const TTriangleFacet& facet ) const
1350     {
1351       const int* tetConn = _connectivity;
1352       for ( ; tetConn[0] >= 0; tetConn += 4 )
1353         if (( facet.contains( tetConn[0] ) +
1354               facet.contains( tetConn[1] ) +
1355               facet.contains( tetConn[2] ) +
1356               facet.contains( tetConn[3] )) == 3 )
1357           return true;
1358       return false;
1359     }
1360   };
1361
1362   //=======================================================================
1363   /*!
1364    * \brief return TSplitMethod for the given element
1365    */
1366   //=======================================================================
1367
1368   TSplitMethod getSplitMethod( SMDS_VolumeTool& vol, const int theMethodFlags)
1369   {
1370     const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1371
1372     // at HEXA_TO_24 method, each face of volume is split into triangles each based on
1373     // an edge and a face barycenter; tertaherdons are based on triangles and
1374     // a volume barycenter
1375     const bool is24TetMode = ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_24 );
1376
1377     // Find out how adjacent volumes are split
1378
1379     vector < list< TTriangleFacet > > triaSplitsByFace( vol.NbFaces() ); // splits of each side
1380     int hasAdjacentSplits = 0, maxTetConnSize = 0;
1381     for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1382     {
1383       int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1384       maxTetConnSize += 4 * ( nbNodes - (is24TetMode ? 0 : 2));
1385       if ( nbNodes < 4 ) continue;
1386
1387       list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1388       const int* nInd = vol.GetFaceNodesIndices( iF );
1389       if ( nbNodes == 4 )
1390       {
1391         TTriangleFacet t012( nInd[0*iQ], nInd[1*iQ], nInd[2*iQ] );
1392         TTriangleFacet t123( nInd[1*iQ], nInd[2*iQ], nInd[3*iQ] );
1393         if      ( t012.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t012 );
1394         else if ( t123.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t123 );
1395       }
1396       else
1397       {
1398         int iCom = 0; // common node of triangle faces to split into
1399         for ( int iVar = 0; iVar < nbNodes; ++iVar, ++iCom )
1400         {
1401           TTriangleFacet t012( nInd[ iQ * ( iCom             )],
1402                                nInd[ iQ * ( (iCom+1)%nbNodes )],
1403                                nInd[ iQ * ( (iCom+2)%nbNodes )]);
1404           TTriangleFacet t023( nInd[ iQ * ( iCom             )],
1405                                nInd[ iQ * ( (iCom+2)%nbNodes )],
1406                                nInd[ iQ * ( (iCom+3)%nbNodes )]);
1407           if ( t012.hasAdjacentTetra( vol.Element() ) && t023.hasAdjacentTetra( vol.Element() ))
1408           {
1409             triaSplits.push_back( t012 );
1410             triaSplits.push_back( t023 );
1411             break;
1412           }
1413         }
1414       }
1415       if ( !triaSplits.empty() )
1416         hasAdjacentSplits = true;
1417     }
1418
1419     // Among variants of split method select one compliant with adjacent volumes
1420
1421     TSplitMethod method;
1422     if ( !vol.Element()->IsPoly() && !is24TetMode )
1423     {
1424       int nbVariants = 2, nbTet = 0;
1425       const int** connVariants = 0;
1426       switch ( vol.Element()->GetEntityType() )
1427       {
1428       case SMDSEntity_Hexa:
1429       case SMDSEntity_Quad_Hexa:
1430       case SMDSEntity_TriQuad_Hexa:
1431         if ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_5 )
1432           connVariants = theHexTo5, nbTet = 5;
1433         else
1434           connVariants = theHexTo6, nbTet = 6, nbVariants = 4;
1435         break;
1436       case SMDSEntity_Pyramid:
1437       case SMDSEntity_Quad_Pyramid:
1438         connVariants = thePyraTo2;  nbTet = 2;
1439         break;
1440       case SMDSEntity_Penta:
1441       case SMDSEntity_Quad_Penta:
1442         connVariants = thePentaTo3; nbTet = 3; nbVariants = 6;
1443         break;
1444       default:
1445         nbVariants = 0;
1446       }
1447       for ( int variant = 0; variant < nbVariants && method._nbTetra == 0; ++variant )
1448       {
1449         // check method compliancy with adjacent tetras,
1450         // all found splits must be among facets of tetras described by this method
1451         method = TSplitMethod( nbTet, connVariants[variant] );
1452         if ( hasAdjacentSplits && method._nbTetra > 0 )
1453         {
1454           bool facetCreated = true;
1455           for ( int iF = 0; facetCreated && iF < triaSplitsByFace.size(); ++iF )
1456           {
1457             list< TTriangleFacet >::const_iterator facet = triaSplitsByFace[iF].begin();
1458             for ( ; facetCreated && facet != triaSplitsByFace[iF].end(); ++facet )
1459               facetCreated = method.hasFacet( *facet );
1460           }
1461           if ( !facetCreated )
1462             method = TSplitMethod(0); // incompatible method
1463         }
1464       }
1465     }
1466     if ( method._nbTetra < 1 )
1467     {
1468       // No standard method is applicable, use a generic solution:
1469       // each facet of a volume is split into triangles and
1470       // each of triangles and a volume barycenter form a tetrahedron.
1471
1472       const bool isHex27 = ( vol.Element()->GetEntityType() == SMDSEntity_TriQuad_Hexa );
1473
1474       int* connectivity = new int[ maxTetConnSize + 1 ];
1475       method._connectivity = connectivity;
1476       method._ownConn = true;
1477       method._baryNode = !isHex27; // to create central node or not
1478
1479       int connSize = 0;
1480       int baryCenInd = vol.NbNodes() - int( isHex27 );
1481       for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1482       {
1483         const int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1484         const int*   nInd = vol.GetFaceNodesIndices( iF );
1485         // find common node of triangle facets of tetra to create
1486         int iCommon = 0; // index in linear numeration
1487         const list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1488         if ( !triaSplits.empty() )
1489         {
1490           // by found facets
1491           const TTriangleFacet* facet = &triaSplits.front();
1492           for ( ; iCommon < nbNodes-1 ; ++iCommon )
1493             if ( facet->contains( nInd[ iQ * iCommon ]) &&
1494                  facet->contains( nInd[ iQ * ((iCommon+2)%nbNodes) ]))
1495               break;
1496         }
1497         else if ( nbNodes > 3 && !is24TetMode )
1498         {
1499           // find the best method of splitting into triangles by aspect ratio
1500           SMESH::Controls::NumericalFunctorPtr aspectRatio( new SMESH::Controls::AspectRatio);
1501           map< double, int > badness2iCommon;
1502           const SMDS_MeshNode** nodes = vol.GetFaceNodes( iF );
1503           int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1504           for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCommon )
1505           {
1506             double badness = 0;
1507             for ( int iLast = iCommon+2; iLast < iCommon+nbNodes; ++iLast )
1508             {
1509               SMDS_FaceOfNodes tria ( nodes[ iQ*( iCommon         )],
1510                                       nodes[ iQ*((iLast-1)%nbNodes)],
1511                                       nodes[ iQ*((iLast  )%nbNodes)]);
1512               badness += getBadRate( &tria, aspectRatio );
1513             }
1514             badness2iCommon.insert( make_pair( badness, iCommon ));
1515           }
1516           // use iCommon with lowest badness
1517           iCommon = badness2iCommon.begin()->second;
1518         }
1519         if ( iCommon >= nbNodes )
1520           iCommon = 0; // something wrong
1521
1522         // fill connectivity of tetrahedra based on a current face
1523         int nbTet = nbNodes - 2;
1524         if ( is24TetMode && nbNodes > 3 && triaSplits.empty())
1525         {
1526           int faceBaryCenInd;
1527           if ( isHex27 )
1528           {
1529             faceBaryCenInd = vol.GetCenterNodeIndex( iF );
1530             method._faceBaryNode[ iF ] = vol.GetNodes()[ faceBaryCenInd ];
1531           }
1532           else
1533           {
1534             method._faceBaryNode[ iF ] = 0;
1535             faceBaryCenInd = baryCenInd + method._faceBaryNode.size();
1536           }
1537           nbTet = nbNodes;
1538           for ( int i = 0; i < nbTet; ++i )
1539           {
1540             int i1 = i, i2 = (i+1) % nbNodes;
1541             if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1542             connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1543             connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1544             connectivity[ connSize++ ] = faceBaryCenInd;
1545             connectivity[ connSize++ ] = baryCenInd;
1546           }
1547         }
1548         else
1549         {
1550           for ( int i = 0; i < nbTet; ++i )
1551           {
1552             int i1 = (iCommon+1+i) % nbNodes, i2 = (iCommon+2+i) % nbNodes;
1553             if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1554             connectivity[ connSize++ ] = nInd[ iQ * iCommon ];
1555             connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1556             connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1557             connectivity[ connSize++ ] = baryCenInd;
1558           }
1559         }
1560         method._nbTetra += nbTet;
1561
1562       } // loop on volume faces
1563
1564       connectivity[ connSize++ ] = -1;
1565
1566     } // end of generic solution
1567
1568     return method;
1569   }
1570   //================================================================================
1571   /*!
1572    * \brief Check if there is a tetraherdon adjacent to the given element via this facet
1573    */
1574   //================================================================================
1575
1576   bool TTriangleFacet::hasAdjacentTetra( const SMDS_MeshElement* elem ) const
1577   {
1578     // find the tetrahedron including the three nodes of facet
1579     const SMDS_MeshNode* n1 = elem->GetNode(_n1);
1580     const SMDS_MeshNode* n2 = elem->GetNode(_n2);
1581     const SMDS_MeshNode* n3 = elem->GetNode(_n3);
1582     SMDS_ElemIteratorPtr volIt1 = n1->GetInverseElementIterator(SMDSAbs_Volume);
1583     while ( volIt1->more() )
1584     {
1585       const SMDS_MeshElement* v = volIt1->next();
1586       SMDSAbs_EntityType type = v->GetEntityType();
1587       if ( type != SMDSEntity_Tetra && type != SMDSEntity_Quad_Tetra )
1588         continue;
1589       if ( type == SMDSEntity_Quad_Tetra && v->GetNodeIndex( n1 ) > 3 )
1590         continue; // medium node not allowed
1591       const int ind2 = v->GetNodeIndex( n2 );
1592       if ( ind2 < 0 || 3 < ind2 )
1593         continue;
1594       const int ind3 = v->GetNodeIndex( n3 );
1595       if ( ind3 < 0 || 3 < ind3 )
1596         continue;
1597       return true;
1598     }
1599     return false;
1600   }
1601
1602   //=======================================================================
1603   /*!
1604    * \brief A key of a face of volume
1605    */
1606   //=======================================================================
1607
1608   struct TVolumeFaceKey: pair< pair< int, int>, pair< int, int> >
1609   {
1610     TVolumeFaceKey( SMDS_VolumeTool& vol, int iF )
1611     {
1612       TIDSortedNodeSet sortedNodes;
1613       const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1614       int nbNodes = vol.NbFaceNodes( iF );
1615       const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iF );
1616       for ( int i = 0; i < nbNodes; i += iQ )
1617         sortedNodes.insert( fNodes[i] );
1618       TIDSortedNodeSet::iterator n = sortedNodes.begin();
1619       first.first   = (*(n++))->GetID();
1620       first.second  = (*(n++))->GetID();
1621       second.first  = (*(n++))->GetID();
1622       second.second = ( sortedNodes.size() > 3 ) ? (*(n++))->GetID() : 0;
1623     }
1624   };
1625 } // namespace
1626
1627 //=======================================================================
1628 //function : SplitVolumesIntoTetra
1629 //purpose  : Split volume elements into tetrahedra.
1630 //=======================================================================
1631
1632 void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
1633                                               const int                theMethodFlags)
1634 {
1635   // std-like iterator on coordinates of nodes of mesh element
1636   typedef SMDS_StdIterator< SMESH_TNodeXYZ, SMDS_ElemIteratorPtr > NXyzIterator;
1637   NXyzIterator xyzEnd;
1638
1639   SMDS_VolumeTool    volTool;
1640   SMESH_MesherHelper helper( *GetMesh());
1641
1642   SMESHDS_SubMesh* subMesh = 0;//GetMeshDS()->MeshElements(1);
1643   SMESHDS_SubMesh* fSubMesh = 0;//subMesh;
1644   
1645   SMESH_SequenceOfElemPtr newNodes, newElems;
1646
1647   // map face of volume to it's baricenrtic node
1648   map< TVolumeFaceKey, const SMDS_MeshNode* > volFace2BaryNode;
1649   double bc[3];
1650
1651   TIDSortedElemSet::const_iterator elem = theElems.begin();
1652   for ( ; elem != theElems.end(); ++elem )
1653   {
1654     if ( (*elem)->GetType() != SMDSAbs_Volume )
1655       continue;
1656     SMDSAbs_EntityType geomType = (*elem)->GetEntityType();
1657     if ( geomType == SMDSEntity_Tetra || geomType == SMDSEntity_Quad_Tetra )
1658       continue;
1659
1660     if ( !volTool.Set( *elem, /*ignoreCentralNodes=*/false )) continue; // strange...
1661
1662     TSplitMethod splitMethod = getSplitMethod( volTool, theMethodFlags );
1663     if ( splitMethod._nbTetra < 1 ) continue;
1664
1665     // find submesh to add new tetras to
1666     if ( !subMesh || !subMesh->Contains( *elem ))
1667     {
1668       int shapeID = FindShape( *elem );
1669       helper.SetSubShape( shapeID ); // helper will add tetras to the found submesh
1670       subMesh = GetMeshDS()->MeshElements( shapeID );
1671     }
1672     int iQ;
1673     if ( (*elem)->IsQuadratic() )
1674     {
1675       iQ = 2;
1676       // add quadratic links to the helper
1677       for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1678       {
1679         const SMDS_MeshNode** fNodes = volTool.GetFaceNodes( iF );
1680         int nbN = volTool.NbFaceNodes( iF ) - bool( volTool.GetCenterNodeIndex(iF) > 0 );
1681         for ( int iN = 0; iN < nbN; iN += iQ )
1682           helper.AddTLinkNode( fNodes[iN], fNodes[iN+2], fNodes[iN+1] );
1683       }
1684       helper.SetIsQuadratic( true );
1685     }
1686     else
1687     {
1688       iQ = 1;
1689       helper.SetIsQuadratic( false );
1690     }
1691     vector<const SMDS_MeshNode*> nodes( (*elem)->begin_nodes(), (*elem)->end_nodes() );
1692     helper.SetElementsOnShape( true );
1693     if ( splitMethod._baryNode )
1694     {
1695       // make a node at barycenter
1696       volTool.GetBaryCenter( bc[0], bc[1], bc[2] );
1697       SMDS_MeshNode* gcNode = helper.AddNode( bc[0], bc[1], bc[2] );
1698       nodes.push_back( gcNode );
1699       newNodes.Append( gcNode );
1700     }
1701     if ( !splitMethod._faceBaryNode.empty() )
1702     {
1703       // make or find baricentric nodes of faces
1704       map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.begin();
1705       for ( ; iF_n != splitMethod._faceBaryNode.end(); ++iF_n )
1706       {
1707         map< TVolumeFaceKey, const SMDS_MeshNode* >::iterator f_n =
1708           volFace2BaryNode.insert
1709           ( make_pair( TVolumeFaceKey( volTool,iF_n->first ), iF_n->second )).first;
1710         if ( !f_n->second )
1711         {
1712           volTool.GetFaceBaryCenter( iF_n->first, bc[0], bc[1], bc[2] );
1713           newNodes.Append( f_n->second = helper.AddNode( bc[0], bc[1], bc[2] ));
1714         }
1715         nodes.push_back( iF_n->second = f_n->second );
1716       }
1717     }
1718
1719     // make tetras
1720     vector<const SMDS_MeshElement* > tetras( splitMethod._nbTetra ); // splits of a volume
1721     const int* tetConn = splitMethod._connectivity;
1722     for ( int i = 0; i < splitMethod._nbTetra; ++i, tetConn += 4 )
1723       newElems.Append( tetras[ i ] = helper.AddVolume( nodes[ tetConn[0] ],
1724                                                        nodes[ tetConn[1] ],
1725                                                        nodes[ tetConn[2] ],
1726                                                        nodes[ tetConn[3] ]));
1727
1728     ReplaceElemInGroups( *elem, tetras, GetMeshDS() );
1729
1730     // Split faces on sides of the split volume
1731
1732     const SMDS_MeshNode** volNodes = volTool.GetNodes();
1733     for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1734     {
1735       const int nbNodes = volTool.NbFaceNodes( iF ) / iQ;
1736       if ( nbNodes < 4 ) continue;
1737
1738       // find an existing face
1739       vector<const SMDS_MeshNode*> fNodes( volTool.GetFaceNodes( iF ),
1740                                            volTool.GetFaceNodes( iF ) + volTool.NbFaceNodes( iF ));
1741       while ( const SMDS_MeshElement* face = GetMeshDS()->FindElement( fNodes, SMDSAbs_Face,
1742                                                                        /*noMedium=*/false))
1743       {
1744         // make triangles
1745         helper.SetElementsOnShape( false );
1746         vector< const SMDS_MeshElement* > triangles;
1747
1748         // find submesh to add new triangles in
1749         if ( !fSubMesh || !fSubMesh->Contains( face ))
1750         {
1751           int shapeID = FindShape( face );
1752           fSubMesh = GetMeshDS()->MeshElements( shapeID );
1753         }
1754         map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.find(iF);
1755         if ( iF_n != splitMethod._faceBaryNode.end() )
1756         {
1757           for ( int iN = 0; iN < nbNodes*iQ; iN += iQ )
1758           {
1759             const SMDS_MeshNode* n1 = fNodes[iN];
1760             const SMDS_MeshNode *n2 = fNodes[(iN+iQ)%(nbNodes*iQ)];
1761             const SMDS_MeshNode *n3 = iF_n->second;
1762             if ( !volTool.IsFaceExternal( iF ))
1763               swap( n2, n3 );
1764             triangles.push_back( helper.AddFace( n1,n2,n3 ));
1765
1766             if ( fSubMesh && n3->getshapeId() < 1 )
1767               fSubMesh->AddNode( n3 );
1768           }
1769         }
1770         else
1771         {
1772           // among possible triangles create ones discribed by split method
1773           const int* nInd = volTool.GetFaceNodesIndices( iF );
1774           int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1775           int iCom = 0; // common node of triangle faces to split into
1776           list< TTriangleFacet > facets;
1777           for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCom )
1778           {
1779             TTriangleFacet t012( nInd[ iQ * ( iCom                )],
1780                                  nInd[ iQ * ( (iCom+1)%nbNodes )],
1781                                  nInd[ iQ * ( (iCom+2)%nbNodes )]);
1782             TTriangleFacet t023( nInd[ iQ * ( iCom                )],
1783                                  nInd[ iQ * ( (iCom+2)%nbNodes )],
1784                                  nInd[ iQ * ( (iCom+3)%nbNodes )]);
1785             if ( splitMethod.hasFacet( t012 ) && splitMethod.hasFacet( t023 ))
1786             {
1787               facets.push_back( t012 );
1788               facets.push_back( t023 );
1789               for ( int iLast = iCom+4; iLast < iCom+nbNodes; ++iLast )
1790                 facets.push_back( TTriangleFacet( nInd[ iQ * ( iCom             )],
1791                                                   nInd[ iQ * ((iLast-1)%nbNodes )],
1792                                                   nInd[ iQ * ((iLast  )%nbNodes )]));
1793               break;
1794             }
1795           }
1796           list< TTriangleFacet >::iterator facet = facets.begin();
1797           for ( ; facet != facets.end(); ++facet )
1798           {
1799             if ( !volTool.IsFaceExternal( iF ))
1800               swap( facet->_n2, facet->_n3 );
1801             triangles.push_back( helper.AddFace( volNodes[ facet->_n1 ],
1802                                                  volNodes[ facet->_n2 ],
1803                                                  volNodes[ facet->_n3 ]));
1804           }
1805         }
1806         for ( int i = 0; i < triangles.size(); ++i )
1807         {
1808           if ( !triangles[i] ) continue;
1809           if ( fSubMesh )
1810             fSubMesh->AddElement( triangles[i]);
1811           newElems.Append( triangles[i] );
1812         }
1813         ReplaceElemInGroups( face, triangles, GetMeshDS() );
1814         GetMeshDS()->RemoveFreeElement( face, fSubMesh, /*fromGroups=*/false );
1815       }
1816
1817     } // loop on volume faces to split them into triangles
1818
1819     GetMeshDS()->RemoveFreeElement( *elem, subMesh, /*fromGroups=*/false );
1820
1821     if ( geomType == SMDSEntity_TriQuad_Hexa )
1822     {
1823       // remove medium nodes that could become free
1824       for ( int i = 20; i < volTool.NbNodes(); ++i )
1825         if ( volNodes[i]->NbInverseElements() == 0 )
1826           GetMeshDS()->RemoveNode( volNodes[i] );
1827     }
1828   } // loop on volumes to split
1829
1830   myLastCreatedNodes = newNodes;
1831   myLastCreatedElems = newElems;
1832 }
1833
1834 //=======================================================================
1835 //function : AddToSameGroups
1836 //purpose  : add elemToAdd to the groups the elemInGroups belongs to
1837 //=======================================================================
1838
1839 void SMESH_MeshEditor::AddToSameGroups (const SMDS_MeshElement* elemToAdd,
1840                                         const SMDS_MeshElement* elemInGroups,
1841                                         SMESHDS_Mesh *          aMesh)
1842 {
1843   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1844   if (!groups.empty()) {
1845     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1846     for ( ; grIt != groups.end(); grIt++ ) {
1847       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1848       if ( group && group->Contains( elemInGroups ))
1849         group->SMDSGroup().Add( elemToAdd );
1850     }
1851   }
1852 }
1853
1854
1855 //=======================================================================
1856 //function : RemoveElemFromGroups
1857 //purpose  : Remove removeelem to the groups the elemInGroups belongs to
1858 //=======================================================================
1859 void SMESH_MeshEditor::RemoveElemFromGroups (const SMDS_MeshElement* removeelem,
1860                                              SMESHDS_Mesh *          aMesh)
1861 {
1862   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1863   if (!groups.empty())
1864   {
1865     set<SMESHDS_GroupBase*>::const_iterator GrIt = groups.begin();
1866     for (; GrIt != groups.end(); GrIt++)
1867     {
1868       SMESHDS_Group* grp = dynamic_cast<SMESHDS_Group*>(*GrIt);
1869       if (!grp || grp->IsEmpty()) continue;
1870       grp->SMDSGroup().Remove(removeelem);
1871     }
1872   }
1873 }
1874
1875 //================================================================================
1876 /*!
1877  * \brief Replace elemToRm by elemToAdd in the all groups
1878  */
1879 //================================================================================
1880
1881 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
1882                                             const SMDS_MeshElement* elemToAdd,
1883                                             SMESHDS_Mesh *          aMesh)
1884 {
1885   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1886   if (!groups.empty()) {
1887     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1888     for ( ; grIt != groups.end(); grIt++ ) {
1889       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1890       if ( group && group->SMDSGroup().Remove( elemToRm ) && elemToAdd )
1891         group->SMDSGroup().Add( elemToAdd );
1892     }
1893   }
1894 }
1895
1896 //================================================================================
1897 /*!
1898  * \brief Replace elemToRm by elemToAdd in the all groups
1899  */
1900 //================================================================================
1901
1902 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement*                elemToRm,
1903                                             const vector<const SMDS_MeshElement*>& elemToAdd,
1904                                             SMESHDS_Mesh *                         aMesh)
1905 {
1906   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1907   if (!groups.empty())
1908   {
1909     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1910     for ( ; grIt != groups.end(); grIt++ ) {
1911       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1912       if ( group && group->SMDSGroup().Remove( elemToRm ) )
1913         for ( int i = 0; i < elemToAdd.size(); ++i )
1914           group->SMDSGroup().Add( elemToAdd[ i ] );
1915     }
1916   }
1917 }
1918
1919 //=======================================================================
1920 //function : QuadToTri
1921 //purpose  : Cut quadrangles into triangles.
1922 //           theCrit is used to select a diagonal to cut
1923 //=======================================================================
1924
1925 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
1926                                   const bool         the13Diag)
1927 {
1928   myLastCreatedElems.Clear();
1929   myLastCreatedNodes.Clear();
1930
1931   MESSAGE( "::QuadToTri()" );
1932
1933   SMESHDS_Mesh * aMesh = GetMeshDS();
1934
1935   Handle(Geom_Surface) surface;
1936   SMESH_MesherHelper   helper( *GetMesh() );
1937
1938   TIDSortedElemSet::iterator itElem;
1939   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1940     const SMDS_MeshElement* elem = *itElem;
1941     if ( !elem || elem->GetType() != SMDSAbs_Face )
1942       continue;
1943     bool isquad = elem->NbNodes()==4 || elem->NbNodes()==8;
1944     if(!isquad) continue;
1945
1946     if(elem->NbNodes()==4) {
1947       // retrieve element nodes
1948       const SMDS_MeshNode* aNodes [4];
1949       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1950       int i = 0;
1951       while ( itN->more() )
1952         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1953
1954       int aShapeId = FindShape( elem );
1955       const SMDS_MeshElement* newElem1 = 0;
1956       const SMDS_MeshElement* newElem2 = 0;
1957       if ( the13Diag ) {
1958         newElem1 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
1959         newElem2 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1960       }
1961       else {
1962         newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1963         newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
1964       }
1965       myLastCreatedElems.Append(newElem1);
1966       myLastCreatedElems.Append(newElem2);
1967       // put a new triangle on the same shape and add to the same groups
1968       if ( aShapeId )
1969         {
1970           aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1971           aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1972         }
1973       AddToSameGroups( newElem1, elem, aMesh );
1974       AddToSameGroups( newElem2, elem, aMesh );
1975       //aMesh->RemoveFreeElement(elem, aMesh->MeshElements(aShapeId), true);
1976       aMesh->RemoveElement( elem );
1977     }
1978
1979     // Quadratic quadrangle
1980
1981     if( elem->NbNodes()==8 && elem->IsQuadratic() ) {
1982
1983       // get surface elem is on
1984       int aShapeId = FindShape( elem );
1985       if ( aShapeId != helper.GetSubShapeID() ) {
1986         surface.Nullify();
1987         TopoDS_Shape shape;
1988         if ( aShapeId > 0 )
1989           shape = aMesh->IndexToShape( aShapeId );
1990         if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1991           TopoDS_Face face = TopoDS::Face( shape );
1992           surface = BRep_Tool::Surface( face );
1993           if ( !surface.IsNull() )
1994             helper.SetSubShape( shape );
1995         }
1996       }
1997
1998       const SMDS_MeshNode* aNodes [8];
1999       const SMDS_MeshNode* inFaceNode = 0;
2000       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2001       int i = 0;
2002       while ( itN->more() ) {
2003         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
2004         if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
2005              aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
2006         {
2007           inFaceNode = aNodes[ i-1 ];
2008         }
2009       }
2010
2011       // find middle point for (0,1,2,3)
2012       // and create a node in this point;
2013       gp_XYZ p( 0,0,0 );
2014       if ( surface.IsNull() ) {
2015         for(i=0; i<4; i++)
2016           p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
2017         p /= 4;
2018       }
2019       else {
2020         TopoDS_Face geomFace = TopoDS::Face( helper.GetSubShape() );
2021         gp_XY uv( 0,0 );
2022         for(i=0; i<4; i++)
2023           uv += helper.GetNodeUV( geomFace, aNodes[i], inFaceNode );
2024         uv /= 4.;
2025         p = surface->Value( uv.X(), uv.Y() ).XYZ();
2026       }
2027       const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
2028       myLastCreatedNodes.Append(newN);
2029
2030       // create a new element
2031       const SMDS_MeshElement* newElem1 = 0;
2032       const SMDS_MeshElement* newElem2 = 0;
2033       if ( the13Diag ) {
2034         newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
2035                                   aNodes[6], aNodes[7], newN );
2036         newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
2037                                   newN,      aNodes[4], aNodes[5] );
2038       }
2039       else {
2040         newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
2041                                   aNodes[7], aNodes[4], newN );
2042         newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
2043                                   newN,      aNodes[5], aNodes[6] );
2044       }
2045       myLastCreatedElems.Append(newElem1);
2046       myLastCreatedElems.Append(newElem2);
2047       // put a new triangle on the same shape and add to the same groups
2048       if ( aShapeId )
2049         {
2050           aMesh->SetMeshElementOnShape( newElem1, aShapeId );
2051           aMesh->SetMeshElementOnShape( newElem2, aShapeId );
2052         }
2053       AddToSameGroups( newElem1, elem, aMesh );
2054       AddToSameGroups( newElem2, elem, aMesh );
2055       aMesh->RemoveElement( elem );
2056     }
2057   }
2058
2059   return true;
2060 }
2061
2062 //=======================================================================
2063 //function : getAngle
2064 //purpose  :
2065 //=======================================================================
2066
2067 double getAngle(const SMDS_MeshElement * tr1,
2068                 const SMDS_MeshElement * tr2,
2069                 const SMDS_MeshNode *    n1,
2070                 const SMDS_MeshNode *    n2)
2071 {
2072   double angle = 2. * M_PI; // bad angle
2073
2074   // get normals
2075   SMESH::Controls::TSequenceOfXYZ P1, P2;
2076   if ( !SMESH::Controls::NumericalFunctor::GetPoints( tr1, P1 ) ||
2077        !SMESH::Controls::NumericalFunctor::GetPoints( tr2, P2 ))
2078     return angle;
2079   gp_Vec N1,N2;
2080   if(!tr1->IsQuadratic())
2081     N1 = gp_Vec( P1(2) - P1(1) ) ^ gp_Vec( P1(3) - P1(1) );
2082   else
2083     N1 = gp_Vec( P1(3) - P1(1) ) ^ gp_Vec( P1(5) - P1(1) );
2084   if ( N1.SquareMagnitude() <= gp::Resolution() )
2085     return angle;
2086   if(!tr2->IsQuadratic())
2087     N2 = gp_Vec( P2(2) - P2(1) ) ^ gp_Vec( P2(3) - P2(1) );
2088   else
2089     N2 = gp_Vec( P2(3) - P2(1) ) ^ gp_Vec( P2(5) - P2(1) );
2090   if ( N2.SquareMagnitude() <= gp::Resolution() )
2091     return angle;
2092
2093   // find the first diagonal node n1 in the triangles:
2094   // take in account a diagonal link orientation
2095   const SMDS_MeshElement *nFirst[2], *tr[] = { tr1, tr2 };
2096   for ( int t = 0; t < 2; t++ ) {
2097     SMDS_ElemIteratorPtr it = tr[ t ]->nodesIterator();
2098     int i = 0, iDiag = -1;
2099     while ( it->more()) {
2100       const SMDS_MeshElement *n = it->next();
2101       if ( n == n1 || n == n2 ) {
2102         if ( iDiag < 0)
2103           iDiag = i;
2104         else {
2105           if ( i - iDiag == 1 )
2106             nFirst[ t ] = ( n == n1 ? n2 : n1 );
2107           else
2108             nFirst[ t ] = n;
2109           break;
2110         }
2111       }
2112       i++;
2113     }
2114   }
2115   if ( nFirst[ 0 ] == nFirst[ 1 ] )
2116     N2.Reverse();
2117
2118   angle = N1.Angle( N2 );
2119   //SCRUTE( angle );
2120   return angle;
2121 }
2122
2123 // =================================================
2124 // class generating a unique ID for a pair of nodes
2125 // and able to return nodes by that ID
2126 // =================================================
2127 class LinkID_Gen {
2128 public:
2129
2130   LinkID_Gen( const SMESHDS_Mesh* theMesh )
2131     :myMesh( theMesh ), myMaxID( theMesh->MaxNodeID() + 1)
2132   {}
2133
2134   long GetLinkID (const SMDS_MeshNode * n1,
2135                   const SMDS_MeshNode * n2) const
2136   {
2137     return ( Min(n1->GetID(),n2->GetID()) * myMaxID + Max(n1->GetID(),n2->GetID()));
2138   }
2139
2140   bool GetNodes (const long             theLinkID,
2141                  const SMDS_MeshNode* & theNode1,
2142                  const SMDS_MeshNode* & theNode2) const
2143   {
2144     theNode1 = myMesh->FindNode( theLinkID / myMaxID );
2145     if ( !theNode1 ) return false;
2146     theNode2 = myMesh->FindNode( theLinkID % myMaxID );
2147     if ( !theNode2 ) return false;
2148     return true;
2149   }
2150
2151 private:
2152   LinkID_Gen();
2153   const SMESHDS_Mesh* myMesh;
2154   long                myMaxID;
2155 };
2156
2157
2158 //=======================================================================
2159 //function : TriToQuad
2160 //purpose  : Fuse neighbour triangles into quadrangles.
2161 //           theCrit is used to select a neighbour to fuse with.
2162 //           theMaxAngle is a max angle between element normals at which
2163 //           fusion is still performed.
2164 //=======================================================================
2165
2166 bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet &                   theElems,
2167                                   SMESH::Controls::NumericalFunctorPtr theCrit,
2168                                   const double                         theMaxAngle)
2169 {
2170   myLastCreatedElems.Clear();
2171   myLastCreatedNodes.Clear();
2172
2173   MESSAGE( "::TriToQuad()" );
2174
2175   if ( !theCrit.get() )
2176     return false;
2177
2178   SMESHDS_Mesh * aMesh = GetMeshDS();
2179
2180   // Prepare data for algo: build
2181   // 1. map of elements with their linkIDs
2182   // 2. map of linkIDs with their elements
2183
2184   map< SMESH_TLink, list< const SMDS_MeshElement* > > mapLi_listEl;
2185   map< SMESH_TLink, list< const SMDS_MeshElement* > >::iterator itLE;
2186   map< const SMDS_MeshElement*, set< SMESH_TLink > >  mapEl_setLi;
2187   map< const SMDS_MeshElement*, set< SMESH_TLink > >::iterator itEL;
2188
2189   TIDSortedElemSet::iterator itElem;
2190   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2191     const SMDS_MeshElement* elem = *itElem;
2192     if(!elem || elem->GetType() != SMDSAbs_Face ) continue;
2193     bool IsTria = elem->NbNodes()==3 || (elem->NbNodes()==6 && elem->IsQuadratic());
2194     if(!IsTria) continue;
2195
2196     // retrieve element nodes
2197     const SMDS_MeshNode* aNodes [4];
2198     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2199     int i = 0;
2200     while ( i<3 )
2201       aNodes[ i++ ] = cast2Node( itN->next() );
2202     aNodes[ 3 ] = aNodes[ 0 ];
2203
2204     // fill maps
2205     for ( i = 0; i < 3; i++ ) {
2206       SMESH_TLink link( aNodes[i], aNodes[i+1] );
2207       // check if elements sharing a link can be fused
2208       itLE = mapLi_listEl.find( link );
2209       if ( itLE != mapLi_listEl.end() ) {
2210         if ((*itLE).second.size() > 1 ) // consider only 2 elems adjacent by a link
2211           continue;
2212         const SMDS_MeshElement* elem2 = (*itLE).second.front();
2213         //if ( FindShape( elem ) != FindShape( elem2 ))
2214         //  continue; // do not fuse triangles laying on different shapes
2215         if ( getAngle( elem, elem2, aNodes[i], aNodes[i+1] ) > theMaxAngle )
2216           continue; // avoid making badly shaped quads
2217         (*itLE).second.push_back( elem );
2218       }
2219       else {
2220         mapLi_listEl[ link ].push_back( elem );
2221       }
2222       mapEl_setLi [ elem ].insert( link );
2223     }
2224   }
2225   // Clean the maps from the links shared by a sole element, ie
2226   // links to which only one element is bound in mapLi_listEl
2227
2228   for ( itLE = mapLi_listEl.begin(); itLE != mapLi_listEl.end(); itLE++ ) {
2229     int nbElems = (*itLE).second.size();
2230     if ( nbElems < 2  ) {
2231       const SMDS_MeshElement* elem = (*itLE).second.front();
2232       SMESH_TLink link = (*itLE).first;
2233       mapEl_setLi[ elem ].erase( link );
2234       if ( mapEl_setLi[ elem ].empty() )
2235         mapEl_setLi.erase( elem );
2236     }
2237   }
2238
2239   // Algo: fuse triangles into quadrangles
2240
2241   while ( ! mapEl_setLi.empty() ) {
2242     // Look for the start element:
2243     // the element having the least nb of shared links
2244     const SMDS_MeshElement* startElem = 0;
2245     int minNbLinks = 4;
2246     for ( itEL = mapEl_setLi.begin(); itEL != mapEl_setLi.end(); itEL++ ) {
2247       int nbLinks = (*itEL).second.size();
2248       if ( nbLinks < minNbLinks ) {
2249         startElem = (*itEL).first;
2250         minNbLinks = nbLinks;
2251         if ( minNbLinks == 1 )
2252           break;
2253       }
2254     }
2255
2256     // search elements to fuse starting from startElem or links of elements
2257     // fused earlyer - startLinks
2258     list< SMESH_TLink > startLinks;
2259     while ( startElem || !startLinks.empty() ) {
2260       while ( !startElem && !startLinks.empty() ) {
2261         // Get an element to start, by a link
2262         SMESH_TLink linkId = startLinks.front();
2263         startLinks.pop_front();
2264         itLE = mapLi_listEl.find( linkId );
2265         if ( itLE != mapLi_listEl.end() ) {
2266           list< const SMDS_MeshElement* > & listElem = (*itLE).second;
2267           list< const SMDS_MeshElement* >::iterator itE = listElem.begin();
2268           for ( ; itE != listElem.end() ; itE++ )
2269             if ( mapEl_setLi.find( (*itE) ) != mapEl_setLi.end() )
2270               startElem = (*itE);
2271           mapLi_listEl.erase( itLE );
2272         }
2273       }
2274
2275       if ( startElem ) {
2276         // Get candidates to be fused
2277         const SMDS_MeshElement *tr1 = startElem, *tr2 = 0, *tr3 = 0;
2278         const SMESH_TLink *link12, *link13;
2279         startElem = 0;
2280         ASSERT( mapEl_setLi.find( tr1 ) != mapEl_setLi.end() );
2281         set< SMESH_TLink >& setLi = mapEl_setLi[ tr1 ];
2282         ASSERT( !setLi.empty() );
2283         set< SMESH_TLink >::iterator itLi;
2284         for ( itLi = setLi.begin(); itLi != setLi.end(); itLi++ )
2285         {
2286           const SMESH_TLink & link = (*itLi);
2287           itLE = mapLi_listEl.find( link );
2288           if ( itLE == mapLi_listEl.end() )
2289             continue;
2290
2291           const SMDS_MeshElement* elem = (*itLE).second.front();
2292           if ( elem == tr1 )
2293             elem = (*itLE).second.back();
2294           mapLi_listEl.erase( itLE );
2295           if ( mapEl_setLi.find( elem ) == mapEl_setLi.end())
2296             continue;
2297           if ( tr2 ) {
2298             tr3 = elem;
2299             link13 = &link;
2300           }
2301           else {
2302             tr2 = elem;
2303             link12 = &link;
2304           }
2305
2306           // add other links of elem to list of links to re-start from
2307           set< SMESH_TLink >& links = mapEl_setLi[ elem ];
2308           set< SMESH_TLink >::iterator it;
2309           for ( it = links.begin(); it != links.end(); it++ ) {
2310             const SMESH_TLink& link2 = (*it);
2311             if ( link2 != link )
2312               startLinks.push_back( link2 );
2313           }
2314         }
2315
2316         // Get nodes of possible quadrangles
2317         const SMDS_MeshNode *n12 [4], *n13 [4];
2318         bool Ok12 = false, Ok13 = false;
2319         const SMDS_MeshNode *linkNode1, *linkNode2;
2320         if(tr2) {
2321           linkNode1 = link12->first;
2322           linkNode2 = link12->second;
2323           if ( tr2 && getQuadrangleNodes( n12, linkNode1, linkNode2, tr1, tr2 ))
2324             Ok12 = true;
2325         }
2326         if(tr3) {
2327           linkNode1 = link13->first;
2328           linkNode2 = link13->second;
2329           if ( tr3 && getQuadrangleNodes( n13, linkNode1, linkNode2, tr1, tr3 ))
2330             Ok13 = true;
2331         }
2332
2333         // Choose a pair to fuse
2334         if ( Ok12 && Ok13 ) {
2335           SMDS_FaceOfNodes quad12 ( n12[ 0 ], n12[ 1 ], n12[ 2 ], n12[ 3 ] );
2336           SMDS_FaceOfNodes quad13 ( n13[ 0 ], n13[ 1 ], n13[ 2 ], n13[ 3 ] );
2337           double aBadRate12 = getBadRate( &quad12, theCrit );
2338           double aBadRate13 = getBadRate( &quad13, theCrit );
2339           if (  aBadRate13 < aBadRate12 )
2340             Ok12 = false;
2341           else
2342             Ok13 = false;
2343         }
2344
2345         // Make quadrangles
2346         // and remove fused elems and removed links from the maps
2347         mapEl_setLi.erase( tr1 );
2348         if ( Ok12 ) {
2349           mapEl_setLi.erase( tr2 );
2350           mapLi_listEl.erase( *link12 );
2351           if(tr1->NbNodes()==3) {
2352             const SMDS_MeshElement* newElem = 0;
2353             newElem = aMesh->AddFace(n12[0], n12[1], n12[2], n12[3] );
2354             myLastCreatedElems.Append(newElem);
2355             AddToSameGroups( newElem, tr1, aMesh );
2356             int aShapeId = tr1->getshapeId();
2357             if ( aShapeId )
2358               {
2359                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2360               }
2361             aMesh->RemoveElement( tr1 );
2362             aMesh->RemoveElement( tr2 );
2363           }
2364           else {
2365             const SMDS_MeshNode* N1 [6];
2366             const SMDS_MeshNode* N2 [6];
2367             GetNodesFromTwoTria(tr1,tr2,N1,N2);
2368             // now we receive following N1 and N2 (using numeration as above image)
2369             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
2370             // i.e. first nodes from both arrays determ new diagonal
2371             const SMDS_MeshNode* aNodes[8];
2372             aNodes[0] = N1[0];
2373             aNodes[1] = N1[1];
2374             aNodes[2] = N2[0];
2375             aNodes[3] = N2[1];
2376             aNodes[4] = N1[3];
2377             aNodes[5] = N2[5];
2378             aNodes[6] = N2[3];
2379             aNodes[7] = N1[5];
2380             const SMDS_MeshElement* newElem = 0;
2381             newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2382                                      aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
2383             myLastCreatedElems.Append(newElem);
2384             AddToSameGroups( newElem, tr1, aMesh );
2385             int aShapeId = tr1->getshapeId();
2386             if ( aShapeId )
2387               {
2388                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2389               }
2390             aMesh->RemoveElement( tr1 );
2391             aMesh->RemoveElement( tr2 );
2392             // remove middle node (9)
2393             GetMeshDS()->RemoveNode( N1[4] );
2394           }
2395         }
2396         else if ( Ok13 ) {
2397           mapEl_setLi.erase( tr3 );
2398           mapLi_listEl.erase( *link13 );
2399           if(tr1->NbNodes()==3) {
2400             const SMDS_MeshElement* newElem = 0;
2401             newElem = aMesh->AddFace(n13[0], n13[1], n13[2], n13[3] );
2402             myLastCreatedElems.Append(newElem);
2403             AddToSameGroups( newElem, tr1, aMesh );
2404             int aShapeId = tr1->getshapeId();
2405             if ( aShapeId )
2406               {
2407                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2408               }
2409             aMesh->RemoveElement( tr1 );
2410             aMesh->RemoveElement( tr3 );
2411           }
2412           else {
2413             const SMDS_MeshNode* N1 [6];
2414             const SMDS_MeshNode* N2 [6];
2415             GetNodesFromTwoTria(tr1,tr3,N1,N2);
2416             // now we receive following N1 and N2 (using numeration as above image)
2417             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
2418             // i.e. first nodes from both arrays determ new diagonal
2419             const SMDS_MeshNode* aNodes[8];
2420             aNodes[0] = N1[0];
2421             aNodes[1] = N1[1];
2422             aNodes[2] = N2[0];
2423             aNodes[3] = N2[1];
2424             aNodes[4] = N1[3];
2425             aNodes[5] = N2[5];
2426             aNodes[6] = N2[3];
2427             aNodes[7] = N1[5];
2428             const SMDS_MeshElement* newElem = 0;
2429             newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2430                                      aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
2431             myLastCreatedElems.Append(newElem);
2432             AddToSameGroups( newElem, tr1, aMesh );
2433             int aShapeId = tr1->getshapeId();
2434             if ( aShapeId )
2435               {
2436                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2437               }
2438             aMesh->RemoveElement( tr1 );
2439             aMesh->RemoveElement( tr3 );
2440             // remove middle node (9)
2441             GetMeshDS()->RemoveNode( N1[4] );
2442           }
2443         }
2444
2445         // Next element to fuse: the rejected one
2446         if ( tr3 )
2447           startElem = Ok12 ? tr3 : tr2;
2448
2449       } // if ( startElem )
2450     } // while ( startElem || !startLinks.empty() )
2451   } // while ( ! mapEl_setLi.empty() )
2452
2453   return true;
2454 }
2455
2456
2457 /*#define DUMPSO(txt) \
2458 //  cout << txt << endl;
2459 //=============================================================================
2460 //
2461 //
2462 //
2463 //=============================================================================
2464 static void swap( int i1, int i2, int idNodes[], gp_Pnt P[] )
2465 {
2466 if ( i1 == i2 )
2467 return;
2468 int tmp = idNodes[ i1 ];
2469 idNodes[ i1 ] = idNodes[ i2 ];
2470 idNodes[ i2 ] = tmp;
2471 gp_Pnt Ptmp = P[ i1 ];
2472 P[ i1 ] = P[ i2 ];
2473 P[ i2 ] = Ptmp;
2474 DUMPSO( i1 << "(" << idNodes[ i2 ] << ") <-> " << i2 << "(" << idNodes[ i1 ] << ")");
2475 }
2476
2477 //=======================================================================
2478 //function : SortQuadNodes
2479 //purpose  : Set 4 nodes of a quadrangle face in a good order.
2480 //           Swap 1<->2 or 2<->3 nodes and correspondingly return
2481 //           1 or 2 else 0.
2482 //=======================================================================
2483
2484 int SMESH_MeshEditor::SortQuadNodes (const SMDS_Mesh * theMesh,
2485 int               idNodes[] )
2486 {
2487   gp_Pnt P[4];
2488   int i;
2489   for ( i = 0; i < 4; i++ ) {
2490     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2491     if ( !n ) return 0;
2492     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2493   }
2494
2495   gp_Vec V1(P[0], P[1]);
2496   gp_Vec V2(P[0], P[2]);
2497   gp_Vec V3(P[0], P[3]);
2498
2499   gp_Vec Cross1 = V1 ^ V2;
2500   gp_Vec Cross2 = V2 ^ V3;
2501
2502   i = 0;
2503   if (Cross1.Dot(Cross2) < 0)
2504   {
2505     Cross1 = V2 ^ V1;
2506     Cross2 = V1 ^ V3;
2507
2508     if (Cross1.Dot(Cross2) < 0)
2509       i = 2;
2510     else
2511       i = 1;
2512     swap ( i, i + 1, idNodes, P );
2513
2514     //     for ( int ii = 0; ii < 4; ii++ ) {
2515     //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2516     //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2517     //     }
2518   }
2519   return i;
2520 }
2521
2522 //=======================================================================
2523 //function : SortHexaNodes
2524 //purpose  : Set 8 nodes of a hexahedron in a good order.
2525 //           Return success status
2526 //=======================================================================
2527
2528 bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh,
2529                                       int               idNodes[] )
2530 {
2531   gp_Pnt P[8];
2532   int i;
2533   DUMPSO( "INPUT: ========================================");
2534   for ( i = 0; i < 8; i++ ) {
2535     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2536     if ( !n ) return false;
2537     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2538     DUMPSO( i << "(" << idNodes[i] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2539   }
2540   DUMPSO( "========================================");
2541
2542
2543   set<int> faceNodes;  // ids of bottom face nodes, to be found
2544   set<int> checkedId1; // ids of tried 2-nd nodes
2545   Standard_Real leastDist = DBL_MAX; // dist of the 4-th node from 123 plane
2546   const Standard_Real tol = 1.e-6;   // tolerance to find nodes in plane
2547   int iMin, iLoop1 = 0;
2548
2549   // Loop to try the 2-nd nodes
2550
2551   while ( leastDist > DBL_MIN && ++iLoop1 < 8 )
2552   {
2553     // Find not checked 2-nd node
2554     for ( i = 1; i < 8; i++ )
2555       if ( checkedId1.find( idNodes[i] ) == checkedId1.end() ) {
2556         int id1 = idNodes[i];
2557         swap ( 1, i, idNodes, P );
2558         checkedId1.insert ( id1 );
2559         break;
2560       }
2561
2562     // Find the 3-d node so that 1-2-3 triangle to be on a hexa face,
2563     // ie that all but meybe one (id3 which is on the same face) nodes
2564     // lay on the same side from the triangle plane.
2565
2566     bool manyInPlane = false; // more than 4 nodes lay in plane
2567     int iLoop2 = 0;
2568     while ( ++iLoop2 < 6 ) {
2569
2570       // get 1-2-3 plane coeffs
2571       Standard_Real A, B, C, D;
2572       gp_Vec N = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2573       if ( N.SquareMagnitude() > gp::Resolution() )
2574       {
2575         gp_Pln pln ( P[0], N );
2576         pln.Coefficients( A, B, C, D );
2577
2578         // find the node (iMin) closest to pln
2579         Standard_Real dist[ 8 ], minDist = DBL_MAX;
2580         set<int> idInPln;
2581         for ( i = 3; i < 8; i++ ) {
2582           dist[i] = A * P[i].X() + B * P[i].Y() + C * P[i].Z() + D;
2583           if ( fabs( dist[i] ) < minDist ) {
2584             minDist = fabs( dist[i] );
2585             iMin = i;
2586           }
2587           if ( fabs( dist[i] ) <= tol )
2588             idInPln.insert( idNodes[i] );
2589         }
2590
2591         // there should not be more than 4 nodes in bottom plane
2592         if ( idInPln.size() > 1 )
2593         {
2594           DUMPSO( "### idInPln.size() = " << idInPln.size());
2595           // idInPlane does not contain the first 3 nodes
2596           if ( manyInPlane || idInPln.size() == 5)
2597             return false; // all nodes in one plane
2598           manyInPlane = true;
2599
2600           // set the 1-st node to be not in plane
2601           for ( i = 3; i < 8; i++ ) {
2602             if ( idInPln.find( idNodes[ i ] ) == idInPln.end() ) {
2603               DUMPSO( "### Reset 0-th node");
2604               swap( 0, i, idNodes, P );
2605               break;
2606             }
2607           }
2608
2609           // reset to re-check second nodes
2610           leastDist = DBL_MAX;
2611           faceNodes.clear();
2612           checkedId1.clear();
2613           iLoop1 = 0;
2614           break; // from iLoop2;
2615         }
2616
2617         // check that the other 4 nodes are on the same side
2618         bool sameSide = true;
2619         bool isNeg = dist[ iMin == 3 ? 4 : 3 ] <= 0.;
2620         for ( i = 3; sameSide && i < 8; i++ ) {
2621           if ( i != iMin )
2622             sameSide = ( isNeg == dist[i] <= 0.);
2623         }
2624
2625         // keep best solution
2626         if ( sameSide && minDist < leastDist ) {
2627           leastDist = minDist;
2628           faceNodes.clear();
2629           faceNodes.insert( idNodes[ 1 ] );
2630           faceNodes.insert( idNodes[ 2 ] );
2631           faceNodes.insert( idNodes[ iMin ] );
2632           DUMPSO( "loop " << iLoop2 << " id2 " << idNodes[ 1 ] << " id3 " << idNodes[ 2 ]
2633                   << " leastDist = " << leastDist);
2634           if ( leastDist <= DBL_MIN )
2635             break;
2636         }
2637       }
2638
2639       // set next 3-d node to check
2640       int iNext = 2 + iLoop2;
2641       if ( iNext < 8 ) {
2642         DUMPSO( "Try 2-nd");
2643         swap ( 2, iNext, idNodes, P );
2644       }
2645     } // while ( iLoop2 < 6 )
2646   } // iLoop1
2647
2648   if ( faceNodes.empty() ) return false;
2649
2650   // Put the faceNodes in proper places
2651   for ( i = 4; i < 8; i++ ) {
2652     if ( faceNodes.find( idNodes[ i ] ) != faceNodes.end() ) {
2653       // find a place to put
2654       int iTo = 1;
2655       while ( faceNodes.find( idNodes[ iTo ] ) != faceNodes.end() )
2656         iTo++;
2657       DUMPSO( "Set faceNodes");
2658       swap ( iTo, i, idNodes, P );
2659     }
2660   }
2661
2662
2663   // Set nodes of the found bottom face in good order
2664   DUMPSO( " Found bottom face: ");
2665   i = SortQuadNodes( theMesh, idNodes );
2666   if ( i ) {
2667     gp_Pnt Ptmp = P[ i ];
2668     P[ i ] = P[ i+1 ];
2669     P[ i+1 ] = Ptmp;
2670   }
2671   //   else
2672   //     for ( int ii = 0; ii < 4; ii++ ) {
2673   //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2674   //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2675   //    }
2676
2677   // Gravity center of the top and bottom faces
2678   gp_Pnt aGCb = ( P[0].XYZ() + P[1].XYZ() + P[2].XYZ() + P[3].XYZ() ) / 4.;
2679   gp_Pnt aGCt = ( P[4].XYZ() + P[5].XYZ() + P[6].XYZ() + P[7].XYZ() ) / 4.;
2680
2681   // Get direction from the bottom to the top face
2682   gp_Vec upDir ( aGCb, aGCt );
2683   Standard_Real upDirSize = upDir.Magnitude();
2684   if ( upDirSize <= gp::Resolution() ) return false;
2685   upDir / upDirSize;
2686
2687   // Assure that the bottom face normal points up
2688   gp_Vec Nb = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2689   Nb += gp_Vec (P[0], P[2]).Crossed( gp_Vec (P[0], P[3]) );
2690   if ( Nb.Dot( upDir ) < 0 ) {
2691     DUMPSO( "Reverse bottom face");
2692     swap( 1, 3, idNodes, P );
2693   }
2694
2695   // Find 5-th node - the one closest to the 1-st among the last 4 nodes.
2696   Standard_Real minDist = DBL_MAX;
2697   for ( i = 4; i < 8; i++ ) {
2698     // projection of P[i] to the plane defined by P[0] and upDir
2699     gp_Pnt Pp = P[i].Translated( upDir * ( upDir.Dot( gp_Vec( P[i], P[0] ))));
2700     Standard_Real sqDist = P[0].SquareDistance( Pp );
2701     if ( sqDist < minDist ) {
2702       minDist = sqDist;
2703       iMin = i;
2704     }
2705   }
2706   DUMPSO( "Set 4-th");
2707   swap ( 4, iMin, idNodes, P );
2708
2709   // Set nodes of the top face in good order
2710   DUMPSO( "Sort top face");
2711   i = SortQuadNodes( theMesh, &idNodes[4] );
2712   if ( i ) {
2713     i += 4;
2714     gp_Pnt Ptmp = P[ i ];
2715     P[ i ] = P[ i+1 ];
2716     P[ i+1 ] = Ptmp;
2717   }
2718
2719   // Assure that direction of the top face normal is from the bottom face
2720   gp_Vec Nt = gp_Vec (P[4], P[5]).Crossed( gp_Vec (P[4], P[6]) );
2721   Nt += gp_Vec (P[4], P[6]).Crossed( gp_Vec (P[4], P[7]) );
2722   if ( Nt.Dot( upDir ) < 0 ) {
2723     DUMPSO( "Reverse top face");
2724     swap( 5, 7, idNodes, P );
2725   }
2726
2727   //   DUMPSO( "OUTPUT: ========================================");
2728   //   for ( i = 0; i < 8; i++ ) {
2729   //     float *p = ugrid->GetPoint(idNodes[i]);
2730   //     DUMPSO( i << "(" << idNodes[i] << ") : " << p[0] << " " << p[1] << " " << p[2]);
2731   //   }
2732
2733   return true;
2734 }*/
2735
2736 //================================================================================
2737 /*!
2738  * \brief Return nodes linked to the given one
2739  * \param theNode - the node
2740  * \param linkedNodes - the found nodes
2741  * \param type - the type of elements to check
2742  *
2743  * Medium nodes are ignored
2744  */
2745 //================================================================================
2746
2747 void SMESH_MeshEditor::GetLinkedNodes( const SMDS_MeshNode* theNode,
2748                                        TIDSortedElemSet &   linkedNodes,
2749                                        SMDSAbs_ElementType  type )
2750 {
2751   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(type);
2752   while ( elemIt->more() )
2753   {
2754     const SMDS_MeshElement* elem = elemIt->next();
2755     if(elem->GetType() == SMDSAbs_0DElement)
2756       continue;
2757     
2758     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
2759     if ( elem->GetType() == SMDSAbs_Volume )
2760     {
2761       SMDS_VolumeTool vol( elem );
2762       while ( nodeIt->more() ) {
2763         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2764         if ( theNode != n && vol.IsLinked( theNode, n ))
2765           linkedNodes.insert( n );
2766       }
2767     }
2768     else
2769     {
2770       for ( int i = 0; nodeIt->more(); ++i ) {
2771         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2772         if ( n == theNode ) {
2773           int iBefore = i - 1;
2774           int iAfter  = i + 1;
2775           if ( elem->IsQuadratic() ) {
2776             int nb = elem->NbNodes() / 2;
2777             iAfter  = SMESH_MesherHelper::WrapIndex( iAfter, nb );
2778             iBefore = SMESH_MesherHelper::WrapIndex( iBefore, nb );
2779           }
2780           linkedNodes.insert( elem->GetNodeWrap( iAfter ));
2781           linkedNodes.insert( elem->GetNodeWrap( iBefore ));
2782         }
2783       }
2784     }
2785   }
2786 }
2787
2788 //=======================================================================
2789 //function : laplacianSmooth
2790 //purpose  : pulls theNode toward the center of surrounding nodes directly
2791 //           connected to that node along an element edge
2792 //=======================================================================
2793
2794 void laplacianSmooth(const SMDS_MeshNode*                 theNode,
2795                      const Handle(Geom_Surface)&          theSurface,
2796                      map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2797 {
2798   // find surrounding nodes
2799
2800   TIDSortedElemSet nodeSet;
2801   SMESH_MeshEditor::GetLinkedNodes( theNode, nodeSet, SMDSAbs_Face );
2802
2803   // compute new coodrs
2804
2805   double coord[] = { 0., 0., 0. };
2806   TIDSortedElemSet::iterator nodeSetIt = nodeSet.begin();
2807   for ( ; nodeSetIt != nodeSet.end(); nodeSetIt++ ) {
2808     const SMDS_MeshNode* node = cast2Node(*nodeSetIt);
2809     if ( theSurface.IsNull() ) { // smooth in 3D
2810       coord[0] += node->X();
2811       coord[1] += node->Y();
2812       coord[2] += node->Z();
2813     }
2814     else { // smooth in 2D
2815       ASSERT( theUVMap.find( node ) != theUVMap.end() );
2816       gp_XY* uv = theUVMap[ node ];
2817       coord[0] += uv->X();
2818       coord[1] += uv->Y();
2819     }
2820   }
2821   int nbNodes = nodeSet.size();
2822   if ( !nbNodes )
2823     return;
2824   coord[0] /= nbNodes;
2825   coord[1] /= nbNodes;
2826
2827   if ( !theSurface.IsNull() ) {
2828     ASSERT( theUVMap.find( theNode ) != theUVMap.end() );
2829     theUVMap[ theNode ]->SetCoord( coord[0], coord[1] );
2830     gp_Pnt p3d = theSurface->Value( coord[0], coord[1] );
2831     coord[0] = p3d.X();
2832     coord[1] = p3d.Y();
2833     coord[2] = p3d.Z();
2834   }
2835   else
2836     coord[2] /= nbNodes;
2837
2838   // move node
2839
2840   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(coord[0],coord[1],coord[2]);
2841 }
2842
2843 //=======================================================================
2844 //function : centroidalSmooth
2845 //purpose  : pulls theNode toward the element-area-weighted centroid of the
2846 //           surrounding elements
2847 //=======================================================================
2848
2849 void centroidalSmooth(const SMDS_MeshNode*                 theNode,
2850                       const Handle(Geom_Surface)&          theSurface,
2851                       map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2852 {
2853   gp_XYZ aNewXYZ(0.,0.,0.);
2854   SMESH::Controls::Area anAreaFunc;
2855   double totalArea = 0.;
2856   int nbElems = 0;
2857
2858   // compute new XYZ
2859
2860   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(SMDSAbs_Face);
2861   while ( elemIt->more() )
2862   {
2863     const SMDS_MeshElement* elem = elemIt->next();
2864     nbElems++;
2865
2866     gp_XYZ elemCenter(0.,0.,0.);
2867     SMESH::Controls::TSequenceOfXYZ aNodePoints;
2868     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2869     int nn = elem->NbNodes();
2870     if(elem->IsQuadratic()) nn = nn/2;
2871     int i=0;
2872     //while ( itN->more() ) {
2873     while ( i<nn ) {
2874       const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>( itN->next() );
2875       i++;
2876       gp_XYZ aP( aNode->X(), aNode->Y(), aNode->Z() );
2877       aNodePoints.push_back( aP );
2878       if ( !theSurface.IsNull() ) { // smooth in 2D
2879         ASSERT( theUVMap.find( aNode ) != theUVMap.end() );
2880         gp_XY* uv = theUVMap[ aNode ];
2881         aP.SetCoord( uv->X(), uv->Y(), 0. );
2882       }
2883       elemCenter += aP;
2884     }
2885     double elemArea = anAreaFunc.GetValue( aNodePoints );
2886     totalArea += elemArea;
2887     elemCenter /= nn;
2888     aNewXYZ += elemCenter * elemArea;
2889   }
2890   aNewXYZ /= totalArea;
2891   if ( !theSurface.IsNull() ) {
2892     theUVMap[ theNode ]->SetCoord( aNewXYZ.X(), aNewXYZ.Y() );
2893     aNewXYZ = theSurface->Value( aNewXYZ.X(), aNewXYZ.Y() ).XYZ();
2894   }
2895
2896   // move node
2897
2898   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(aNewXYZ.X(),aNewXYZ.Y(),aNewXYZ.Z());
2899 }
2900
2901 //=======================================================================
2902 //function : getClosestUV
2903 //purpose  : return UV of closest projection
2904 //=======================================================================
2905
2906 static bool getClosestUV (Extrema_GenExtPS& projector,
2907                           const gp_Pnt&     point,
2908                           gp_XY &           result)
2909 {
2910   projector.Perform( point );
2911   if ( projector.IsDone() ) {
2912     double u, v, minVal = DBL_MAX;
2913     for ( int i = projector.NbExt(); i > 0; i-- )
2914 #if OCC_VERSION_LARGE > 0x06040000 // Porting to OCCT6.5.1
2915       if ( projector.SquareDistance( i ) < minVal ) {
2916         minVal = projector.SquareDistance( i );
2917 #else
2918       if ( projector.Value( i ) < minVal ) {
2919         minVal = projector.Value( i );
2920 #endif
2921         projector.Point( i ).Parameter( u, v );
2922       }
2923     result.SetCoord( u, v );
2924     return true;
2925   }
2926   return false;
2927 }
2928
2929 //=======================================================================
2930 //function : Smooth
2931 //purpose  : Smooth theElements during theNbIterations or until a worst
2932 //           element has aspect ratio <= theTgtAspectRatio.
2933 //           Aspect Ratio varies in range [1.0, inf].
2934 //           If theElements is empty, the whole mesh is smoothed.
2935 //           theFixedNodes contains additionally fixed nodes. Nodes built
2936 //           on edges and boundary nodes are always fixed.
2937 //=======================================================================
2938
2939 void SMESH_MeshEditor::Smooth (TIDSortedElemSet &          theElems,
2940                                set<const SMDS_MeshNode*> & theFixedNodes,
2941                                const SmoothMethod          theSmoothMethod,
2942                                const int                   theNbIterations,
2943                                double                      theTgtAspectRatio,
2944                                const bool                  the2D)
2945 {
2946   myLastCreatedElems.Clear();
2947   myLastCreatedNodes.Clear();
2948
2949   MESSAGE((theSmoothMethod==LAPLACIAN ? "LAPLACIAN" : "CENTROIDAL") << "--::Smooth()");
2950
2951   if ( theTgtAspectRatio < 1.0 )
2952     theTgtAspectRatio = 1.0;
2953
2954   const double disttol = 1.e-16;
2955
2956   SMESH::Controls::AspectRatio aQualityFunc;
2957
2958   SMESHDS_Mesh* aMesh = GetMeshDS();
2959
2960   if ( theElems.empty() ) {
2961     // add all faces to theElems
2962     SMDS_FaceIteratorPtr fIt = aMesh->facesIterator();
2963     while ( fIt->more() ) {
2964       const SMDS_MeshElement* face = fIt->next();
2965       theElems.insert( face );
2966     }
2967   }
2968   // get all face ids theElems are on
2969   set< int > faceIdSet;
2970   TIDSortedElemSet::iterator itElem;
2971   if ( the2D )
2972     for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2973       int fId = FindShape( *itElem );
2974       // check that corresponding submesh exists and a shape is face
2975       if (fId &&
2976           faceIdSet.find( fId ) == faceIdSet.end() &&
2977           aMesh->MeshElements( fId )) {
2978         TopoDS_Shape F = aMesh->IndexToShape( fId );
2979         if ( !F.IsNull() && F.ShapeType() == TopAbs_FACE )
2980           faceIdSet.insert( fId );
2981       }
2982     }
2983   faceIdSet.insert( 0 ); // to smooth elements that are not on any TopoDS_Face
2984
2985   // ===============================================
2986   // smooth elements on each TopoDS_Face separately
2987   // ===============================================
2988
2989   set< int >::reverse_iterator fId = faceIdSet.rbegin(); // treate 0 fId at the end
2990   for ( ; fId != faceIdSet.rend(); ++fId ) {
2991     // get face surface and submesh
2992     Handle(Geom_Surface) surface;
2993     SMESHDS_SubMesh* faceSubMesh = 0;
2994     TopoDS_Face face;
2995     double fToler2 = 0, f,l;
2996     double u1 = 0, u2 = 0, v1 = 0, v2 = 0;
2997     bool isUPeriodic = false, isVPeriodic = false;
2998     if ( *fId ) {
2999       face = TopoDS::Face( aMesh->IndexToShape( *fId ));
3000       surface = BRep_Tool::Surface( face );
3001       faceSubMesh = aMesh->MeshElements( *fId );
3002       fToler2 = BRep_Tool::Tolerance( face );
3003       fToler2 *= fToler2 * 10.;
3004       isUPeriodic = surface->IsUPeriodic();
3005       if ( isUPeriodic )
3006         surface->UPeriod();
3007       isVPeriodic = surface->IsVPeriodic();
3008       if ( isVPeriodic )
3009         surface->VPeriod();
3010       surface->Bounds( u1, u2, v1, v2 );
3011     }
3012     // ---------------------------------------------------------
3013     // for elements on a face, find movable and fixed nodes and
3014     // compute UV for them
3015     // ---------------------------------------------------------
3016     bool checkBoundaryNodes = false;
3017     bool isQuadratic = false;
3018     set<const SMDS_MeshNode*> setMovableNodes;
3019     map< const SMDS_MeshNode*, gp_XY* > uvMap, uvMap2;
3020     list< gp_XY > listUV; // uvs the 2 uvMaps refer to
3021     list< const SMDS_MeshElement* > elemsOnFace;
3022
3023     Extrema_GenExtPS projector;
3024     GeomAdaptor_Surface surfAdaptor;
3025     if ( !surface.IsNull() ) {
3026       surfAdaptor.Load( surface );
3027       projector.Initialize( surfAdaptor, 20,20, 1e-5,1e-5 );
3028     }
3029     int nbElemOnFace = 0;
3030     itElem = theElems.begin();
3031     // loop on not yet smoothed elements: look for elems on a face
3032     while ( itElem != theElems.end() ) {
3033       if ( faceSubMesh && nbElemOnFace == faceSubMesh->NbElements() )
3034         break; // all elements found
3035
3036       const SMDS_MeshElement* elem = *itElem;
3037       if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() < 3 ||
3038            ( faceSubMesh && !faceSubMesh->Contains( elem ))) {
3039         ++itElem;
3040         continue;
3041       }
3042       elemsOnFace.push_back( elem );
3043       theElems.erase( itElem++ );
3044       nbElemOnFace++;
3045
3046       if ( !isQuadratic )
3047         isQuadratic = elem->IsQuadratic();
3048
3049       // get movable nodes of elem
3050       const SMDS_MeshNode* node;
3051       SMDS_TypeOfPosition posType;
3052       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
3053       int nn = 0, nbn =  elem->NbNodes();
3054       if(elem->IsQuadratic())
3055         nbn = nbn/2;
3056       while ( nn++ < nbn ) {
3057         node = static_cast<const SMDS_MeshNode*>( itN->next() );
3058         const SMDS_PositionPtr& pos = node->GetPosition();
3059         posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
3060         if (posType != SMDS_TOP_EDGE &&
3061             posType != SMDS_TOP_VERTEX &&
3062             theFixedNodes.find( node ) == theFixedNodes.end())
3063         {
3064           // check if all faces around the node are on faceSubMesh
3065           // because a node on edge may be bound to face
3066           SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
3067           bool all = true;
3068           if ( faceSubMesh ) {
3069             while ( eIt->more() && all ) {
3070               const SMDS_MeshElement* e = eIt->next();
3071               all = faceSubMesh->Contains( e );
3072             }
3073           }
3074           if ( all )
3075             setMovableNodes.insert( node );
3076           else
3077             checkBoundaryNodes = true;
3078         }
3079         if ( posType == SMDS_TOP_3DSPACE )
3080           checkBoundaryNodes = true;
3081       }
3082
3083       if ( surface.IsNull() )
3084         continue;
3085
3086       // get nodes to check UV
3087       list< const SMDS_MeshNode* > uvCheckNodes;
3088       itN = elem->nodesIterator();
3089       nn = 0; nbn =  elem->NbNodes();
3090       if(elem->IsQuadratic())
3091         nbn = nbn/2;
3092       while ( nn++ < nbn ) {
3093         node = static_cast<const SMDS_MeshNode*>( itN->next() );
3094         if ( uvMap.find( node ) == uvMap.end() )
3095           uvCheckNodes.push_back( node );
3096         // add nodes of elems sharing node
3097         //         SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
3098         //         while ( eIt->more() ) {
3099         //           const SMDS_MeshElement* e = eIt->next();
3100         //           if ( e != elem ) {
3101         //             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3102         //             while ( nIt->more() ) {
3103         //               const SMDS_MeshNode* n =
3104         //                 static_cast<const SMDS_MeshNode*>( nIt->next() );
3105         //               if ( uvMap.find( n ) == uvMap.end() )
3106         //                 uvCheckNodes.push_back( n );
3107         //             }
3108         //           }
3109         //         }
3110       }
3111       // check UV on face
3112       list< const SMDS_MeshNode* >::iterator n = uvCheckNodes.begin();
3113       for ( ; n != uvCheckNodes.end(); ++n ) {
3114         node = *n;
3115         gp_XY uv( 0, 0 );
3116         const SMDS_PositionPtr& pos = node->GetPosition();
3117         posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
3118         // get existing UV
3119         switch ( posType ) {
3120         case SMDS_TOP_FACE: {
3121           SMDS_FacePosition* fPos = ( SMDS_FacePosition* ) pos;
3122           uv.SetCoord( fPos->GetUParameter(), fPos->GetVParameter() );
3123           break;
3124         }
3125         case SMDS_TOP_EDGE: {
3126           TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
3127           Handle(Geom2d_Curve) pcurve;
3128           if ( !S.IsNull() && S.ShapeType() == TopAbs_EDGE )
3129             pcurve = BRep_Tool::CurveOnSurface( TopoDS::Edge( S ), face, f,l );
3130           if ( !pcurve.IsNull() ) {
3131             double u = (( SMDS_EdgePosition* ) pos )->GetUParameter();
3132             uv = pcurve->Value( u ).XY();
3133           }
3134           break;
3135         }
3136         case SMDS_TOP_VERTEX: {
3137           TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
3138           if ( !S.IsNull() && S.ShapeType() == TopAbs_VERTEX )
3139             uv = BRep_Tool::Parameters( TopoDS::Vertex( S ), face ).XY();
3140           break;
3141         }
3142         default:;
3143         }
3144         // check existing UV
3145         bool project = true;
3146         gp_Pnt pNode ( node->X(), node->Y(), node->Z() );
3147         double dist1 = DBL_MAX, dist2 = 0;
3148         if ( posType != SMDS_TOP_3DSPACE ) {
3149           dist1 = pNode.SquareDistance( surface->Value( uv.X(), uv.Y() ));
3150           project = dist1 > fToler2;
3151         }
3152         if ( project ) { // compute new UV
3153           gp_XY newUV;
3154           if ( !getClosestUV( projector, pNode, newUV )) {
3155             MESSAGE("Node Projection Failed " << node);
3156           }
3157           else {
3158             if ( isUPeriodic )
3159               newUV.SetX( ElCLib::InPeriod( newUV.X(), u1, u2 ));
3160             if ( isVPeriodic )
3161               newUV.SetY( ElCLib::InPeriod( newUV.Y(), v1, v2 ));
3162             // check new UV
3163             if ( posType != SMDS_TOP_3DSPACE )
3164               dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() ));
3165             if ( dist2 < dist1 )
3166               uv = newUV;
3167           }
3168         }
3169         // store UV in the map
3170         listUV.push_back( uv );
3171         uvMap.insert( make_pair( node, &listUV.back() ));
3172       }
3173     } // loop on not yet smoothed elements
3174
3175     if ( !faceSubMesh || nbElemOnFace != faceSubMesh->NbElements() )
3176       checkBoundaryNodes = true;
3177
3178     // fix nodes on mesh boundary
3179
3180     if ( checkBoundaryNodes ) {
3181       map< SMESH_TLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
3182       map< SMESH_TLink, int >::iterator link_nb;
3183       // put all elements links to linkNbMap
3184       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3185       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3186         const SMDS_MeshElement* elem = (*elemIt);
3187         int nbn =  elem->NbCornerNodes();
3188         // loop on elem links: insert them in linkNbMap
3189         for ( int iN = 0; iN < nbn; ++iN ) {
3190           const SMDS_MeshNode* n1 = elem->GetNode( iN );
3191           const SMDS_MeshNode* n2 = elem->GetNode(( iN+1 ) % nbn);
3192           SMESH_TLink link( n1, n2 );
3193           link_nb = linkNbMap.insert( make_pair( link, 0 )).first;
3194           link_nb->second++;
3195         }
3196       }
3197       // remove nodes that are in links encountered only once from setMovableNodes
3198       for ( link_nb = linkNbMap.begin(); link_nb != linkNbMap.end(); ++link_nb ) {
3199         if ( link_nb->second == 1 ) {
3200           setMovableNodes.erase( link_nb->first.node1() );
3201           setMovableNodes.erase( link_nb->first.node2() );
3202         }
3203       }
3204     }
3205
3206     // -----------------------------------------------------
3207     // for nodes on seam edge, compute one more UV ( uvMap2 );
3208     // find movable nodes linked to nodes on seam and which
3209     // are to be smoothed using the second UV ( uvMap2 )
3210     // -----------------------------------------------------
3211
3212     set<const SMDS_MeshNode*> nodesNearSeam; // to smooth using uvMap2
3213     if ( !surface.IsNull() ) {
3214       TopExp_Explorer eExp( face, TopAbs_EDGE );
3215       for ( ; eExp.More(); eExp.Next() ) {
3216         TopoDS_Edge edge = TopoDS::Edge( eExp.Current() );
3217         if ( !BRep_Tool::IsClosed( edge, face ))
3218           continue;
3219         SMESHDS_SubMesh* sm = aMesh->MeshElements( edge );
3220         if ( !sm ) continue;
3221         // find out which parameter varies for a node on seam
3222         double f,l;
3223         gp_Pnt2d uv1, uv2;
3224         Handle(Geom2d_Curve) pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3225         if ( pcurve.IsNull() ) continue;
3226         uv1 = pcurve->Value( f );
3227         edge.Reverse();
3228         pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3229         if ( pcurve.IsNull() ) continue;
3230         uv2 = pcurve->Value( f );
3231         int iPar = Abs( uv1.X() - uv2.X() ) > Abs( uv1.Y() - uv2.Y() ) ? 1 : 2;
3232         // assure uv1 < uv2
3233         if ( uv1.Coord( iPar ) > uv2.Coord( iPar )) {
3234           gp_Pnt2d tmp = uv1; uv1 = uv2; uv2 = tmp;
3235         }
3236         // get nodes on seam and its vertices
3237         list< const SMDS_MeshNode* > seamNodes;
3238         SMDS_NodeIteratorPtr nSeamIt = sm->GetNodes();
3239         while ( nSeamIt->more() ) {
3240           const SMDS_MeshNode* node = nSeamIt->next();
3241           if ( !isQuadratic || !IsMedium( node ))
3242             seamNodes.push_back( node );
3243         }
3244         TopExp_Explorer vExp( edge, TopAbs_VERTEX );
3245         for ( ; vExp.More(); vExp.Next() ) {
3246           sm = aMesh->MeshElements( vExp.Current() );
3247           if ( sm ) {
3248             nSeamIt = sm->GetNodes();
3249             while ( nSeamIt->more() )
3250               seamNodes.push_back( nSeamIt->next() );
3251           }
3252         }
3253         // loop on nodes on seam
3254         list< const SMDS_MeshNode* >::iterator noSeIt = seamNodes.begin();
3255         for ( ; noSeIt != seamNodes.end(); ++noSeIt ) {
3256           const SMDS_MeshNode* nSeam = *noSeIt;
3257           map< const SMDS_MeshNode*, gp_XY* >::iterator n_uv = uvMap.find( nSeam );
3258           if ( n_uv == uvMap.end() )
3259             continue;
3260           // set the first UV
3261           n_uv->second->SetCoord( iPar, uv1.Coord( iPar ));
3262           // set the second UV
3263           listUV.push_back( *n_uv->second );
3264           listUV.back().SetCoord( iPar, uv2.Coord( iPar ));
3265           if ( uvMap2.empty() )
3266             uvMap2 = uvMap; // copy the uvMap contents
3267           uvMap2[ nSeam ] = &listUV.back();
3268
3269           // collect movable nodes linked to ones on seam in nodesNearSeam
3270           SMDS_ElemIteratorPtr eIt = nSeam->GetInverseElementIterator(SMDSAbs_Face);
3271           while ( eIt->more() ) {
3272             const SMDS_MeshElement* e = eIt->next();
3273             int nbUseMap1 = 0, nbUseMap2 = 0;
3274             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3275             int nn = 0, nbn =  e->NbNodes();
3276             if(e->IsQuadratic()) nbn = nbn/2;
3277             while ( nn++ < nbn )
3278             {
3279               const SMDS_MeshNode* n =
3280                 static_cast<const SMDS_MeshNode*>( nIt->next() );
3281               if (n == nSeam ||
3282                   setMovableNodes.find( n ) == setMovableNodes.end() )
3283                 continue;
3284               // add only nodes being closer to uv2 than to uv1
3285               gp_Pnt pMid (0.5 * ( n->X() + nSeam->X() ),
3286                            0.5 * ( n->Y() + nSeam->Y() ),
3287                            0.5 * ( n->Z() + nSeam->Z() ));
3288               gp_XY uv;
3289               getClosestUV( projector, pMid, uv );
3290               if ( uv.Coord( iPar ) > uvMap[ n ]->Coord( iPar ) ) {
3291                 nodesNearSeam.insert( n );
3292                 nbUseMap2++;
3293               }
3294               else
3295                 nbUseMap1++;
3296             }
3297             // for centroidalSmooth all element nodes must
3298             // be on one side of a seam
3299             if ( theSmoothMethod == CENTROIDAL && nbUseMap1 && nbUseMap2 ) {
3300               SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3301               nn = 0;
3302               while ( nn++ < nbn ) {
3303                 const SMDS_MeshNode* n =
3304                   static_cast<const SMDS_MeshNode*>( nIt->next() );
3305                 setMovableNodes.erase( n );
3306               }
3307             }
3308           }
3309         } // loop on nodes on seam
3310       } // loop on edge of a face
3311     } // if ( !face.IsNull() )
3312
3313     if ( setMovableNodes.empty() ) {
3314       MESSAGE( "Face id : " << *fId << " - NO SMOOTHING: no nodes to move!!!");
3315       continue; // goto next face
3316     }
3317
3318     // -------------
3319     // SMOOTHING //
3320     // -------------
3321
3322     int it = -1;
3323     double maxRatio = -1., maxDisplacement = -1.;
3324     set<const SMDS_MeshNode*>::iterator nodeToMove;
3325     for ( it = 0; it < theNbIterations; it++ ) {
3326       maxDisplacement = 0.;
3327       nodeToMove = setMovableNodes.begin();
3328       for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3329         const SMDS_MeshNode* node = (*nodeToMove);
3330         gp_XYZ aPrevPos ( node->X(), node->Y(), node->Z() );
3331
3332         // smooth
3333         bool map2 = ( nodesNearSeam.find( node ) != nodesNearSeam.end() );
3334         if ( theSmoothMethod == LAPLACIAN )
3335           laplacianSmooth( node, surface, map2 ? uvMap2 : uvMap );
3336         else
3337           centroidalSmooth( node, surface, map2 ? uvMap2 : uvMap );
3338
3339         // node displacement
3340         gp_XYZ aNewPos ( node->X(), node->Y(), node->Z() );
3341         Standard_Real aDispl = (aPrevPos - aNewPos).SquareModulus();
3342         if ( aDispl > maxDisplacement )
3343           maxDisplacement = aDispl;
3344       }
3345       // no node movement => exit
3346       //if ( maxDisplacement < 1.e-16 ) {
3347       if ( maxDisplacement < disttol ) {
3348         MESSAGE("-- no node movement --");
3349         break;
3350       }
3351
3352       // check elements quality
3353       maxRatio  = 0;
3354       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3355       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3356         const SMDS_MeshElement* elem = (*elemIt);
3357         if ( !elem || elem->GetType() != SMDSAbs_Face )
3358           continue;
3359         SMESH::Controls::TSequenceOfXYZ aPoints;
3360         if ( aQualityFunc.GetPoints( elem, aPoints )) {
3361           double aValue = aQualityFunc.GetValue( aPoints );
3362           if ( aValue > maxRatio )
3363             maxRatio = aValue;
3364         }
3365       }
3366       if ( maxRatio <= theTgtAspectRatio ) {
3367         MESSAGE("-- quality achived --");
3368         break;
3369       }
3370       if (it+1 == theNbIterations) {
3371         MESSAGE("-- Iteration limit exceeded --");
3372       }
3373     } // smoothing iterations
3374
3375     MESSAGE(" Face id: " << *fId <<
3376             " Nb iterstions: " << it <<
3377             " Displacement: " << maxDisplacement <<
3378             " Aspect Ratio " << maxRatio);
3379
3380     // ---------------------------------------
3381     // new nodes positions are computed,
3382     // record movement in DS and set new UV
3383     // ---------------------------------------
3384     nodeToMove = setMovableNodes.begin();
3385     for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3386       SMDS_MeshNode* node = const_cast< SMDS_MeshNode* > (*nodeToMove);
3387       aMesh->MoveNode( node, node->X(), node->Y(), node->Z() );
3388       map< const SMDS_MeshNode*, gp_XY* >::iterator node_uv = uvMap.find( node );
3389       if ( node_uv != uvMap.end() ) {
3390         gp_XY* uv = node_uv->second;
3391         node->SetPosition
3392           ( SMDS_PositionPtr( new SMDS_FacePosition( uv->X(), uv->Y() )));
3393       }
3394     }
3395
3396     // move medium nodes of quadratic elements
3397     if ( isQuadratic )
3398     {
3399       SMESH_MesherHelper helper( *GetMesh() );
3400       if ( !face.IsNull() )
3401         helper.SetSubShape( face );
3402       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3403       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3404         const SMDS_VtkFace* QF =
3405           dynamic_cast<const SMDS_VtkFace*> (*elemIt);
3406         if(QF && QF->IsQuadratic()) {
3407           vector<const SMDS_MeshNode*> Ns;
3408           Ns.reserve(QF->NbNodes()+1);
3409           SMDS_ElemIteratorPtr anIter = QF->interlacedNodesElemIterator();
3410           while ( anIter->more() )
3411             Ns.push_back( cast2Node(anIter->next()) );
3412           Ns.push_back( Ns[0] );
3413           double x, y, z;
3414           for(int i=0; i<QF->NbNodes(); i=i+2) {
3415             if ( !surface.IsNull() ) {
3416               gp_XY uv1 = helper.GetNodeUV( face, Ns[i], Ns[i+2] );
3417               gp_XY uv2 = helper.GetNodeUV( face, Ns[i+2], Ns[i] );
3418               gp_XY uv = ( uv1 + uv2 ) / 2.;
3419               gp_Pnt xyz = surface->Value( uv.X(), uv.Y() );
3420               x = xyz.X(); y = xyz.Y(); z = xyz.Z();
3421             }
3422             else {
3423               x = (Ns[i]->X() + Ns[i+2]->X())/2;
3424               y = (Ns[i]->Y() + Ns[i+2]->Y())/2;
3425               z = (Ns[i]->Z() + Ns[i+2]->Z())/2;
3426             }
3427             if( fabs( Ns[i+1]->X() - x ) > disttol ||
3428                 fabs( Ns[i+1]->Y() - y ) > disttol ||
3429                 fabs( Ns[i+1]->Z() - z ) > disttol ) {
3430               // we have to move i+1 node
3431               aMesh->MoveNode( Ns[i+1], x, y, z );
3432             }
3433           }
3434         }
3435       }
3436     }
3437
3438   } // loop on face ids
3439
3440 }
3441
3442 //=======================================================================
3443 //function : isReverse
3444 //purpose  : Return true if normal of prevNodes is not co-directied with
3445 //           gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]).
3446 //           iNotSame is where prevNodes and nextNodes are different.
3447 //           If result is true then future volume orientation is OK
3448 //=======================================================================
3449
3450 static bool isReverse(const SMDS_MeshElement*             face,
3451                       const vector<const SMDS_MeshNode*>& prevNodes,
3452                       const vector<const SMDS_MeshNode*>& nextNodes,
3453                       const int                           iNotSame)
3454 {
3455
3456   SMESH_TNodeXYZ pP = prevNodes[ iNotSame ];
3457   SMESH_TNodeXYZ pN = nextNodes[ iNotSame ];
3458   gp_XYZ extrDir( pN - pP ), faceNorm;
3459   SMESH_Algo::FaceNormal( face, faceNorm, /*normalized=*/false );
3460
3461   return faceNorm * extrDir < 0.0;
3462 }
3463
3464 //=======================================================================
3465 /*!
3466  * \brief Create elements by sweeping an element
3467  * \param elem - element to sweep
3468  * \param newNodesItVec - nodes generated from each node of the element
3469  * \param newElems - generated elements
3470  * \param nbSteps - number of sweeping steps
3471  * \param srcElements - to append elem for each generated element
3472  */
3473 //=======================================================================
3474
3475 void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement*               elem,
3476                                     const vector<TNodeOfNodeListMapItr> & newNodesItVec,
3477                                     list<const SMDS_MeshElement*>&        newElems,
3478                                     const int                             nbSteps,
3479                                     SMESH_SequenceOfElemPtr&              srcElements)
3480 {
3481   //MESSAGE("sweepElement " << nbSteps);
3482   SMESHDS_Mesh* aMesh = GetMeshDS();
3483
3484   const int           nbNodes = elem->NbNodes();          
3485   const int         nbCorners = elem->NbCornerNodes();
3486   SMDSAbs_EntityType baseType = elem->GetEntityType(); /* it can change in case of 
3487                                                           polyhedron creation !!! */
3488   // Loop on elem nodes:
3489   // find new nodes and detect same nodes indices
3490   vector < list< const SMDS_MeshNode* >::const_iterator > itNN( nbNodes );
3491   vector<const SMDS_MeshNode*> prevNod( nbNodes );
3492   vector<const SMDS_MeshNode*> nextNod( nbNodes );
3493   vector<const SMDS_MeshNode*> midlNod( nbNodes );
3494
3495   int iNode, nbSame = 0, nbDouble = 0, iNotSameNode = 0;
3496   vector<int> sames(nbNodes);
3497   vector<bool> isSingleNode(nbNodes);
3498
3499   for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3500     TNodeOfNodeListMapItr                        nnIt = newNodesItVec[ iNode ];
3501     const SMDS_MeshNode*                         node = nnIt->first;
3502     const list< const SMDS_MeshNode* > & listNewNodes = nnIt->second;
3503     if ( listNewNodes.empty() )
3504       return;
3505
3506     itNN   [ iNode ] = listNewNodes.begin();
3507     prevNod[ iNode ] = node;
3508     nextNod[ iNode ] = listNewNodes.front();
3509
3510     isSingleNode[iNode] = (listNewNodes.size()==nbSteps); /* medium node of quadratic or
3511                                                              corner node of linear */
3512     if ( prevNod[ iNode ] != nextNod [ iNode ])
3513       nbDouble += !isSingleNode[iNode];
3514
3515     if( iNode < nbCorners ) { // check corners only
3516       if ( prevNod[ iNode ] == nextNod [ iNode ])
3517         sames[nbSame++] = iNode;
3518       else
3519         iNotSameNode = iNode;
3520     }
3521   }
3522
3523   if ( nbSame == nbNodes || nbSame > 2) {
3524     MESSAGE( " Too many same nodes of element " << elem->GetID() );
3525     return;
3526   }
3527
3528   if ( elem->GetType() == SMDSAbs_Face && !isReverse( elem, prevNod, nextNod, iNotSameNode ))
3529   {
3530     // fix nodes order to have bottom normal external
3531     if ( baseType == SMDSEntity_Polygon )
3532     {
3533       std::reverse( itNN.begin(), itNN.end() );
3534       std::reverse( prevNod.begin(), prevNod.end() );
3535       std::reverse( midlNod.begin(), midlNod.end() );
3536       std::reverse( nextNod.begin(), nextNod.end() );
3537       std::reverse( isSingleNode.begin(), isSingleNode.end() );
3538     }
3539     else
3540     {
3541       const vector<int>& ind = SMDS_MeshCell::reverseSmdsOrder( baseType );
3542       SMDS_MeshCell::applyInterlace( ind, itNN );
3543       SMDS_MeshCell::applyInterlace( ind, prevNod );
3544       SMDS_MeshCell::applyInterlace( ind, nextNod );
3545       SMDS_MeshCell::applyInterlace( ind, midlNod );
3546       SMDS_MeshCell::applyInterlace( ind, isSingleNode );
3547       if ( nbSame > 0 )
3548       {
3549         sames[nbSame] = iNotSameNode;
3550         for ( int j = 0; j <= nbSame; ++j )
3551           for ( size_t i = 0; i < ind.size(); ++i )
3552             if ( ind[i] == sames[j] )
3553             {
3554               sames[j] = i;
3555               break;
3556             }
3557         iNotSameNode = sames[nbSame];
3558       }
3559     }
3560   }
3561
3562   int iSameNode = 0, iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0;
3563   if ( nbSame > 0 ) {
3564     iSameNode    = sames[ nbSame-1 ];
3565     iBeforeSame  = ( iSameNode + nbCorners - 1 ) % nbCorners;
3566     iAfterSame   = ( iSameNode + 1 ) % nbCorners;
3567     iOpposSame   = ( iSameNode - 2 < 0  ? iSameNode + 2 : iSameNode - 2 );
3568   }
3569
3570   // make new elements
3571   for (int iStep = 0; iStep < nbSteps; iStep++ )
3572   {
3573     // get next nodes
3574     for ( iNode = 0; iNode < nbNodes; iNode++ )
3575     {
3576       midlNod[ iNode ] = isSingleNode[iNode] ? 0 : *itNN[ iNode ]++;
3577       nextNod[ iNode ] = *itNN[ iNode ]++;
3578     }
3579
3580     SMDS_MeshElement* aNewElem = 0;
3581     /*if(!elem->IsPoly())*/ {
3582       switch ( baseType ) {
3583       case SMDSEntity_0D:
3584       case SMDSEntity_Node: { // sweep NODE
3585         if ( nbSame == 0 ) {
3586           if ( isSingleNode[0] )
3587             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ] );
3588           else
3589             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ], midlNod[ 0 ] );
3590         }
3591         else
3592           return;
3593         break;
3594       }
3595       case SMDSEntity_Edge: { // sweep EDGE
3596         if ( nbDouble == 0 )
3597         {
3598           if ( nbSame == 0 ) // ---> quadrangle
3599             aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3600                                       nextNod[ 1 ], nextNod[ 0 ] );
3601           else               // ---> triangle
3602             aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3603                                       nextNod[ iNotSameNode ] );
3604         }
3605         else                 // ---> polygon
3606         {
3607           vector<const SMDS_MeshNode*> poly_nodes;
3608           poly_nodes.push_back( prevNod[0] );
3609           poly_nodes.push_back( prevNod[1] );
3610           if ( prevNod[1] != nextNod[1] )
3611           {
3612             if ( midlNod[1]) poly_nodes.push_back( midlNod[1]);
3613             poly_nodes.push_back( nextNod[1] );
3614           }
3615           if ( prevNod[0] != nextNod[0] )
3616           {
3617             poly_nodes.push_back( nextNod[0] );
3618             if ( midlNod[0]) poly_nodes.push_back( midlNod[0]);
3619           }
3620           switch ( poly_nodes.size() ) {
3621           case 3:
3622             aNewElem = aMesh->AddFace( poly_nodes[ 0 ], poly_nodes[ 1 ], poly_nodes[ 2 ]);
3623             break;
3624           case 4:
3625             aNewElem = aMesh->AddFace( poly_nodes[ 0 ], poly_nodes[ 1 ],
3626                                        poly_nodes[ 2 ], poly_nodes[ 3 ]);
3627             break;
3628           default:
3629             aNewElem = aMesh->AddPolygonalFace (poly_nodes);
3630           }
3631         }
3632         break;
3633       }
3634       case SMDSEntity_Triangle: // TRIANGLE --->
3635         {
3636           if ( nbDouble > 0 ) break;
3637           if ( nbSame == 0 )       // ---> pentahedron
3638             aNewElem = aMesh->AddVolume (prevNod[ 0 ], prevNod[ 1 ], prevNod[ 2 ],
3639                                          nextNod[ 0 ], nextNod[ 1 ], nextNod[ 2 ] );
3640
3641           else if ( nbSame == 1 )  // ---> pyramid
3642             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
3643                                          nextNod[ iAfterSame ],  nextNod[ iBeforeSame ],
3644                                          nextNod[ iSameNode ]);
3645
3646           else // 2 same nodes:       ---> tetrahedron
3647             aNewElem = aMesh->AddVolume (prevNod[ 0 ], prevNod[ 1 ], prevNod[ 2 ],
3648                                          nextNod[ iNotSameNode ]);
3649           break;
3650         }
3651       case SMDSEntity_Quad_Edge: // sweep quadratic EDGE --->
3652         {
3653           if ( nbSame == 2 )
3654             return;
3655           if ( nbDouble+nbSame == 2 )
3656           {
3657             if(nbSame==0) {      // ---> quadratic quadrangle
3658               aNewElem = aMesh->AddFace(prevNod[0], prevNod[1], nextNod[1], nextNod[0],
3659                                         prevNod[2], midlNod[1], nextNod[2], midlNod[0]);
3660             }
3661             else { //(nbSame==1) // ---> quadratic triangle
3662               if(sames[0]==2) {
3663                 return; // medium node on axis
3664               }
3665               else if(sames[0]==0)
3666                 aNewElem = aMesh->AddFace(prevNod[0], nextNod[1], prevNod[1],
3667                                           nextNod[2], midlNod[1], prevNod[2]);
3668               else // sames[0]==1
3669                 aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], prevNod[1],
3670                                           midlNod[0], nextNod[2], prevNod[2]);
3671             }
3672           }
3673           else if ( nbDouble == 3 )
3674           {
3675             if ( nbSame == 0 ) {  // ---> bi-quadratic quadrangle
3676               aNewElem = aMesh->AddFace(prevNod[0], prevNod[1], nextNod[1], nextNod[0],
3677                                         prevNod[2], midlNod[1], nextNod[2], midlNod[0], midlNod[2]);
3678             }
3679           }
3680           else
3681             return;
3682           break;
3683         }
3684       case SMDSEntity_Quadrangle: { // sweep QUADRANGLE --->
3685         if ( nbDouble > 0 ) break;
3686
3687         if ( nbSame == 0 )       // ---> hexahedron
3688           aNewElem = aMesh->AddVolume (prevNod[ 0 ], prevNod[ 1 ], prevNod[ 2 ], prevNod[ 3 ],
3689                                        nextNod[ 0 ], nextNod[ 1 ], nextNod[ 2 ], nextNod[ 3 ]);
3690
3691         else if ( nbSame == 1 ) { // ---> pyramid + pentahedron
3692           aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
3693                                        nextNod[ iAfterSame ],  nextNod[ iBeforeSame ],
3694                                        nextNod[ iSameNode ]);
3695           newElems.push_back( aNewElem );
3696           aNewElem = aMesh->AddVolume (prevNod[ iAfterSame ],  prevNod[ iOpposSame ],
3697                                        prevNod[ iBeforeSame ], nextNod[ iAfterSame ],
3698                                        nextNod[ iOpposSame ],  nextNod[ iBeforeSame ] );
3699         }
3700         else if ( nbSame == 2 ) { // ---> pentahedron
3701           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] )
3702             // iBeforeSame is same too
3703             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iOpposSame ],
3704                                          nextNod[ iOpposSame ],  prevNod[ iSameNode ],
3705                                          prevNod[ iAfterSame ],  nextNod[ iAfterSame ]);
3706           else
3707             // iAfterSame is same too
3708             aNewElem = aMesh->AddVolume (prevNod[ iSameNode ],   prevNod[ iBeforeSame ],
3709                                          nextNod[ iBeforeSame ], prevNod[ iAfterSame ],
3710                                          prevNod[ iOpposSame ],  nextNod[ iOpposSame ]);
3711         }
3712         break;
3713       }
3714       case SMDSEntity_Quad_Triangle: { // sweep Quadratic TRIANGLE --->
3715         if ( nbDouble+nbSame != 3 ) break;
3716         if(nbSame==0) {
3717           // --->  pentahedron with 15 nodes
3718           aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
3719                                        nextNod[0], nextNod[1], nextNod[2],
3720                                        prevNod[3], prevNod[4], prevNod[5],
3721                                        nextNod[3], nextNod[4], nextNod[5],
3722                                        midlNod[0], midlNod[1], midlNod[2]);
3723         }
3724         else if(nbSame==1) {
3725           // --->  2d order pyramid of 13 nodes
3726           int apex = iSameNode;
3727           int i0 = ( apex + 1 ) % nbCorners;
3728           int i1 = ( apex - 1 + nbCorners ) % nbCorners;
3729           int i0a = apex + 3;
3730           int i1a = i1 + 3;
3731           int i01 = i0 + 3;
3732           aNewElem = aMesh->AddVolume(prevNod[i1], prevNod[i0],
3733                                       nextNod[i0], nextNod[i1], prevNod[apex],
3734                                       prevNod[i01], midlNod[i0],
3735                                       nextNod[i01], midlNod[i1],
3736                                       prevNod[i1a], prevNod[i0a],
3737                                       nextNod[i0a], nextNod[i1a]);
3738         }
3739         else if(nbSame==2) {
3740           // --->  2d order tetrahedron of 10 nodes
3741           int n1 = iNotSameNode;
3742           int n2 = ( n1 + 1             ) % nbCorners;
3743           int n3 = ( n1 + nbCorners - 1 ) % nbCorners;
3744           int n12 = n1 + 3;
3745           int n23 = n2 + 3;
3746           int n31 = n3 + 3;
3747           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], prevNod[n3], nextNod[n1],
3748                                        prevNod[n12], prevNod[n23], prevNod[n31],
3749                                        midlNod[n1], nextNod[n12], nextNod[n31]);
3750         }
3751         break;
3752       }
3753       case SMDSEntity_Quad_Quadrangle: { // sweep Quadratic QUADRANGLE --->
3754         if ( nbDouble != 4 ) break;
3755         if( nbSame == 0 ) {
3756           // --->  hexahedron with 20 nodes
3757           aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
3758                                        nextNod[0], nextNod[1], nextNod[2], nextNod[3],
3759                                        prevNod[4], prevNod[5], prevNod[6], prevNod[7],
3760                                        nextNod[4], nextNod[5], nextNod[6], nextNod[7],
3761                                        midlNod[0], midlNod[1], midlNod[2], midlNod[3]);
3762         }
3763         else if(nbSame==1) {
3764           // ---> pyramid + pentahedron - can not be created since it is needed 
3765           // additional middle node at the center of face
3766           INFOS( " Sweep for face " << elem->GetID() << " can not be created" );
3767           return;
3768         }
3769         else if( nbSame == 2 ) {
3770           // --->  2d order Pentahedron with 15 nodes
3771           int n1,n2,n4,n5;
3772           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] ) {
3773             // iBeforeSame is same too
3774             n1 = iBeforeSame;
3775             n2 = iOpposSame;
3776             n4 = iSameNode;
3777             n5 = iAfterSame;
3778           }
3779           else {
3780             // iAfterSame is same too
3781             n1 = iSameNode;
3782             n2 = iBeforeSame;
3783             n4 = iAfterSame;
3784             n5 = iOpposSame;
3785           }
3786           int n12 = n2 + 4;
3787           int n45 = n4 + 4;
3788           int n14 = n1 + 4;
3789           int n25 = n5 + 4;
3790           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], nextNod[n2],
3791                                        prevNod[n4], prevNod[n5], nextNod[n5],
3792                                        prevNod[n12], midlNod[n2], nextNod[n12],
3793                                        prevNod[n45], midlNod[n5], nextNod[n45],
3794                                        prevNod[n14], prevNod[n25], nextNod[n25]);
3795         }
3796         break;
3797       }
3798       case SMDSEntity_BiQuad_Quadrangle: { // sweep BiQuadratic QUADRANGLE --->
3799
3800         if( nbSame == 0 && nbDouble == 9 ) {
3801           // --->  tri-quadratic hexahedron with 27 nodes
3802           aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
3803                                        nextNod[0], nextNod[1], nextNod[2], nextNod[3],
3804                                        prevNod[4], prevNod[5], prevNod[6], prevNod[7],
3805                                        nextNod[4], nextNod[5], nextNod[6], nextNod[7],
3806                                        midlNod[0], midlNod[1], midlNod[2], midlNod[3],
3807                                        prevNod[8], // bottom center
3808                                        midlNod[4], midlNod[5], midlNod[6], midlNod[7],
3809                                        nextNod[8], // top center
3810                                        midlNod[8]);// elem center
3811         }
3812         else
3813         {
3814           return;
3815         }
3816         break;
3817       }
3818       case SMDSEntity_Polygon: { // sweep POLYGON
3819
3820         if ( nbNodes == 6 && nbSame == 0 && nbDouble == 0 ) {
3821           // --->  hexagonal prism
3822           aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
3823                                        prevNod[3], prevNod[4], prevNod[5],
3824                                        nextNod[0], nextNod[1], nextNod[2],
3825                                        nextNod[3], nextNod[4], nextNod[5]);
3826         }
3827         break;
3828       }
3829       default:
3830         break;
3831       }
3832     }
3833
3834     if ( !aNewElem && elem->GetType() == SMDSAbs_Face ) // try to create a polyherdal prism
3835     {
3836       if ( baseType != SMDSEntity_Polygon )
3837       {
3838         const std::vector<int>& ind = SMDS_MeshCell::interlacedSmdsOrder(baseType);
3839         SMDS_MeshCell::applyInterlace( ind, prevNod );
3840         SMDS_MeshCell::applyInterlace( ind, nextNod );
3841         SMDS_MeshCell::applyInterlace( ind, midlNod );
3842         SMDS_MeshCell::applyInterlace( ind, itNN );
3843         SMDS_MeshCell::applyInterlace( ind, isSingleNode );
3844         baseType = SMDSEntity_Polygon; // WARNING: change baseType !!!!
3845       }
3846       vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3847       vector<int> quantities (nbNodes + 2);
3848       polyedre_nodes.clear();
3849       quantities.clear();
3850
3851       // bottom of prism
3852       for (int inode = 0; inode < nbNodes; inode++)
3853         polyedre_nodes.push_back( prevNod[inode] );
3854       quantities.push_back( nbNodes );
3855
3856       // top of prism
3857       polyedre_nodes.push_back( nextNod[0] );
3858       for (int inode = nbNodes; inode-1; --inode )
3859         polyedre_nodes.push_back( nextNod[inode-1] );
3860       quantities.push_back( nbNodes );
3861
3862       // side faces
3863       for (int iface = 0; iface < nbNodes; iface++)
3864       {
3865         const int prevNbNodes = polyedre_nodes.size();
3866         int inextface = (iface+1) % nbNodes;
3867         polyedre_nodes.push_back( prevNod[inextface] );
3868         polyedre_nodes.push_back( prevNod[iface] );
3869         if ( prevNod[iface] != nextNod[iface] )
3870         {
3871           if ( midlNod[ iface ]) polyedre_nodes.push_back( midlNod[ iface ]);
3872           polyedre_nodes.push_back( nextNod[iface] );
3873         }
3874         if ( prevNod[inextface] != nextNod[inextface] )
3875         {
3876           polyedre_nodes.push_back( nextNod[inextface] );
3877           if ( midlNod[ inextface ]) polyedre_nodes.push_back( midlNod[ inextface ]);
3878         }
3879         const int nbFaceNodes = polyedre_nodes.size() - prevNbNodes;
3880         if ( nbFaceNodes > 2 )
3881           quantities.push_back( nbFaceNodes );
3882         else // degenerated face
3883           polyedre_nodes.resize( prevNbNodes );
3884       }
3885       aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3886     }
3887
3888     if ( aNewElem ) {
3889       newElems.push_back( aNewElem );
3890       myLastCreatedElems.Append(aNewElem);
3891       srcElements.Append( elem );
3892     }
3893
3894     // set new prev nodes
3895     for ( iNode = 0; iNode < nbNodes; iNode++ )
3896       prevNod[ iNode ] = nextNod[ iNode ];
3897
3898   } // for steps
3899 }
3900
3901 //=======================================================================
3902 /*!
3903  * \brief Create 1D and 2D elements around swept elements
3904  * \param mapNewNodes - source nodes and ones generated from them
3905  * \param newElemsMap - source elements and ones generated from them
3906  * \param elemNewNodesMap - nodes generated from each node of each element
3907  * \param elemSet - all swept elements
3908  * \param nbSteps - number of sweeping steps
3909  * \param srcElements - to append elem for each generated element
3910  */
3911 //=======================================================================
3912
3913 void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap &     mapNewNodes,
3914                                   TElemOfElemListMap &     newElemsMap,
3915                                   TElemOfVecOfNnlmiMap &   elemNewNodesMap,
3916                                   TIDSortedElemSet&        elemSet,
3917                                   const int                nbSteps,
3918                                   SMESH_SequenceOfElemPtr& srcElements)
3919 {
3920   ASSERT( newElemsMap.size() == elemNewNodesMap.size() );
3921   SMESHDS_Mesh* aMesh = GetMeshDS();
3922
3923   // Find nodes belonging to only one initial element - sweep them to get edges.
3924
3925   TNodeOfNodeListMapItr nList = mapNewNodes.begin();
3926   for ( ; nList != mapNewNodes.end(); nList++ )
3927   {
3928     const SMDS_MeshNode* node =
3929       static_cast<const SMDS_MeshNode*>( nList->first );
3930     SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
3931     int nbInitElems = 0;
3932     const SMDS_MeshElement* el = 0;
3933     SMDSAbs_ElementType highType = SMDSAbs_Edge; // count most complex elements only
3934     while ( eIt->more() && nbInitElems < 2 ) {
3935       el = eIt->next();
3936       SMDSAbs_ElementType type = el->GetType();
3937       if ( type == SMDSAbs_Volume || type < highType ) continue;
3938       if ( type > highType ) {
3939         nbInitElems = 0;
3940         highType = type;
3941       }
3942       nbInitElems += elemSet.count(el);
3943     }
3944     if ( nbInitElems < 2 ) {
3945       bool NotCreateEdge = el && el->IsMediumNode(node);
3946       if(!NotCreateEdge) {
3947         vector<TNodeOfNodeListMapItr> newNodesItVec( 1, nList );
3948         list<const SMDS_MeshElement*> newEdges;
3949         sweepElement( node, newNodesItVec, newEdges, nbSteps, srcElements );
3950       }
3951     }
3952   }
3953
3954   // Make a ceiling for each element ie an equal element of last new nodes.
3955   // Find free links of faces - make edges and sweep them into faces.
3956
3957   TElemOfElemListMap::iterator   itElem      = newElemsMap.begin();
3958   TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin();
3959   for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ )
3960   {
3961     const SMDS_MeshElement* elem = itElem->first;
3962     vector<TNodeOfNodeListMapItr>& vecNewNodes = itElemNodes->second;
3963
3964     if(itElem->second.size()==0) continue;
3965
3966     const bool isQuadratic = elem->IsQuadratic();
3967
3968     if ( elem->GetType() == SMDSAbs_Edge ) {
3969       // create a ceiling edge
3970       if ( !isQuadratic ) {
3971         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3972                                vecNewNodes[ 1 ]->second.back())) {
3973           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3974                                                    vecNewNodes[ 1 ]->second.back()));
3975           srcElements.Append( myLastCreatedElems.Last() );
3976         }
3977       }
3978       else {
3979         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3980                                vecNewNodes[ 1 ]->second.back(),
3981                                vecNewNodes[ 2 ]->second.back())) {
3982           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3983                                                    vecNewNodes[ 1 ]->second.back(),
3984                                                    vecNewNodes[ 2 ]->second.back()));
3985           srcElements.Append( myLastCreatedElems.Last() );
3986         }
3987       }
3988     }
3989     if ( elem->GetType() != SMDSAbs_Face )
3990       continue;
3991
3992     bool hasFreeLinks = false;
3993
3994     TIDSortedElemSet avoidSet;
3995     avoidSet.insert( elem );
3996
3997     set<const SMDS_MeshNode*> aFaceLastNodes;
3998     int iNode, nbNodes = vecNewNodes.size();
3999     if ( !isQuadratic ) {
4000       // loop on the face nodes
4001       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
4002         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
4003         // look for free links of the face
4004         int iNext = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1;
4005         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
4006         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
4007         // check if a link is free
4008         if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
4009           hasFreeLinks = true;
4010           // make an edge and a ceiling for a new edge
4011           if ( !aMesh->FindEdge( n1, n2 )) {
4012             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // free link edge
4013             srcElements.Append( myLastCreatedElems.Last() );
4014           }
4015           n1 = vecNewNodes[ iNode ]->second.back();
4016           n2 = vecNewNodes[ iNext ]->second.back();
4017           if ( !aMesh->FindEdge( n1, n2 )) {
4018             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // ceiling edge
4019             srcElements.Append( myLastCreatedElems.Last() );
4020           }
4021         }
4022       }
4023     }
4024     else { // elem is quadratic face
4025       int nbn = nbNodes/2;
4026       for ( iNode = 0; iNode < nbn; iNode++ ) {
4027         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
4028         int iNext = ( iNode + 1 == nbn ) ? 0 : iNode + 1;
4029         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
4030         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
4031         const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first;
4032         // check if a link is free
4033         if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet ) &&
4034              ! SMESH_MeshEditor::FindFaceInSet ( n1, n3, elemSet, avoidSet ) &&
4035              ! SMESH_MeshEditor::FindFaceInSet ( n3, n2, elemSet, avoidSet ) ) {
4036           hasFreeLinks = true;
4037           // make an edge and a ceiling for a new edge
4038           // find medium node
4039           if ( !aMesh->FindEdge( n1, n2, n3 )) {
4040             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // free link edge
4041             srcElements.Append( myLastCreatedElems.Last() );
4042           }
4043           n1 = vecNewNodes[ iNode ]->second.back();
4044           n2 = vecNewNodes[ iNext ]->second.back();
4045           n3 = vecNewNodes[ iNode+nbn ]->second.back();
4046           if ( !aMesh->FindEdge( n1, n2, n3 )) {
4047             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // ceiling edge
4048             srcElements.Append( myLastCreatedElems.Last() );
4049           }
4050         }
4051       }
4052       for ( iNode = nbn; iNode < nbNodes; iNode++ ) {
4053         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
4054       }
4055     }
4056
4057     // sweep free links into faces
4058
4059     if ( hasFreeLinks )  {
4060       list<const SMDS_MeshElement*> & newVolumes = itElem->second;
4061       int iVol, volNb, nbVolumesByStep = newVolumes.size() / nbSteps;
4062
4063       set<const SMDS_MeshNode*> initNodeSet, topNodeSet, faceNodeSet;
4064       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
4065         initNodeSet.insert( vecNewNodes[ iNode ]->first );
4066         topNodeSet .insert( vecNewNodes[ iNode ]->second.back() );
4067       }
4068       for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) {
4069         list<const SMDS_MeshElement*>::iterator v = newVolumes.begin();
4070         std::advance( v, volNb );
4071         // find indices of free faces of a volume and their source edges
4072         list< int > freeInd;
4073         list< const SMDS_MeshElement* > srcEdges; // source edges of free faces
4074         SMDS_VolumeTool vTool( *v, /*ignoreCentralNodes=*/false );
4075         int iF, nbF = vTool.NbFaces();
4076         for ( iF = 0; iF < nbF; iF ++ ) {
4077           if (vTool.IsFreeFace( iF ) &&
4078               vTool.GetFaceNodes( iF, faceNodeSet ) &&
4079               initNodeSet != faceNodeSet) // except an initial face
4080           {
4081             if ( nbSteps == 1 && faceNodeSet == topNodeSet )
4082               continue;
4083             freeInd.push_back( iF );
4084             // find source edge of a free face iF
4085             vector<const SMDS_MeshNode*> commonNodes; // shared by the initial and free faces
4086             commonNodes.resize( initNodeSet.size(), NULL ); // avoid spoiling memory
4087             std::set_intersection( faceNodeSet.begin(), faceNodeSet.end(),
4088                                    initNodeSet.begin(), initNodeSet.end(),
4089                                    commonNodes.begin());
4090             if ( (*v)->IsQuadratic() )
4091               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1],commonNodes[2]));
4092             else
4093               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1]));
4094 #ifdef _DEBUG_
4095             if ( !srcEdges.back() )
4096             {
4097               cout << "SMESH_MeshEditor::makeWalls(), no source edge found for a free face #"
4098                    << iF << " of volume #" << vTool.ID() << endl;
4099             }
4100 #endif
4101           }
4102         }
4103         if ( freeInd.empty() )
4104           continue;
4105
4106         // create faces for all steps;
4107         // if such a face has been already created by sweep of edge,
4108         // assure that its orientation is OK
4109         for ( int iStep = 0; iStep < nbSteps; iStep++ ) {
4110           vTool.Set( *v, /*ignoreCentralNodes=*/false );
4111           vTool.SetExternalNormal();
4112           const int nextShift = vTool.IsForward() ? +1 : -1;
4113           list< int >::iterator ind = freeInd.begin();
4114           list< const SMDS_MeshElement* >::iterator srcEdge = srcEdges.begin();
4115           for ( ; ind != freeInd.end(); ++ind, ++srcEdge ) // loop on free faces
4116           {
4117             const SMDS_MeshNode** nodes = vTool.GetFaceNodes( *ind );
4118             int nbn = vTool.NbFaceNodes( *ind );
4119             const SMDS_MeshElement * f = 0;
4120             if ( nbn == 3 )              ///// triangle
4121             {
4122               f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]);
4123               if ( !f ||
4124                    nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ]) + nextShift ))
4125               {
4126                 const SMDS_MeshNode* newOrder[3] = { nodes[ 1 - nextShift ],
4127                                                      nodes[ 1 ],
4128                                                      nodes[ 1 + nextShift ] };
4129                 if ( f )
4130                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4131                 else
4132                   myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ], newOrder[ 1 ],
4133                                                             newOrder[ 2 ] ));
4134               }
4135             }
4136             else if ( nbn == 4 )       ///// quadrangle
4137             {
4138               f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]);
4139               if ( !f ||
4140                    nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ]) + nextShift ))
4141               {
4142                 const SMDS_MeshNode* newOrder[4] = { nodes[ 0 ], nodes[ 2-nextShift ],
4143                                                      nodes[ 2 ], nodes[ 2+nextShift ] };
4144                 if ( f )
4145                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4146                 else
4147                   myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ], newOrder[ 1 ],
4148                                                             newOrder[ 2 ], newOrder[ 3 ]));
4149               }
4150             }
4151             else if ( nbn == 6 && isQuadratic ) /////// quadratic triangle
4152             {
4153               f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[1], nodes[3], nodes[5] );
4154               if ( !f ||
4155                    nodes[2] != f->GetNodeWrap( f->GetNodeIndex( nodes[0] ) + 2*nextShift ))
4156               {
4157                 const SMDS_MeshNode* newOrder[6] = { nodes[2 - 2*nextShift],
4158                                                      nodes[2],
4159                                                      nodes[2 + 2*nextShift],
4160                                                      nodes[3 - 2*nextShift],
4161                                                      nodes[3],
4162                                                      nodes[3 + 2*nextShift]};
4163                 if ( f )
4164                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4165                 else
4166                   myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ],
4167                                                             newOrder[ 1 ],
4168                                                             newOrder[ 2 ],
4169                                                             newOrder[ 3 ],
4170                                                             newOrder[ 4 ],
4171                                                             newOrder[ 5 ] ));
4172               }
4173             }
4174             else if ( nbn == 8 && isQuadratic ) /////// quadratic quadrangle
4175             {
4176               f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[6],
4177                                    nodes[1], nodes[3], nodes[5], nodes[7] );
4178               if ( !f ||
4179                    nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 2*nextShift ))
4180               {
4181                 const SMDS_MeshNode* newOrder[8] = { nodes[0],
4182                                                      nodes[4 - 2*nextShift],
4183                                                      nodes[4],
4184                                                      nodes[4 + 2*nextShift],
4185                                                      nodes[1],
4186                                                      nodes[5 - 2*nextShift],
4187                                                      nodes[5],
4188                                                      nodes[5 + 2*nextShift] };
4189                 if ( f )
4190                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4191                 else
4192                   myLastCreatedElems.Append(aMesh->AddFace(newOrder[ 0 ], newOrder[ 1 ],
4193                                                            newOrder[ 2 ], newOrder[ 3 ],
4194                                                            newOrder[ 4 ], newOrder[ 5 ],
4195                                                            newOrder[ 6 ], newOrder[ 7 ]));
4196               }
4197             }
4198             else if ( nbn == 9 && isQuadratic ) /////// bi-quadratic quadrangle
4199             {
4200               f = aMesh->FindElement( vector<const SMDS_MeshNode*>( nodes, nodes+nbn ),
4201                                       SMDSAbs_Face, /*noMedium=*/false);
4202               if ( !f ||
4203                    nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 2*nextShift ))
4204               {
4205                 const SMDS_MeshNode* newOrder[9] = { nodes[0],
4206                                                      nodes[4 - 2*nextShift],
4207                                                      nodes[4],
4208                                                      nodes[4 + 2*nextShift],
4209                                                      nodes[1],
4210                                                      nodes[5 - 2*nextShift],
4211                                                      nodes[5],
4212                                                      nodes[5 + 2*nextShift],
4213                                                      nodes[8] };
4214                 if ( f )
4215                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4216                 else
4217                   myLastCreatedElems.Append(aMesh->AddFace(newOrder[ 0 ], newOrder[ 1 ],
4218                                                            newOrder[ 2 ], newOrder[ 3 ],
4219                                                            newOrder[ 4 ], newOrder[ 5 ],
4220                                                            newOrder[ 6 ], newOrder[ 7 ],
4221                                                            newOrder[ 8 ]));
4222               }
4223             }
4224             else  //////// polygon
4225             {
4226               vector<const SMDS_MeshNode*> polygon_nodes ( nodes, nodes+nbn );
4227               const SMDS_MeshFace * f = aMesh->FindFace( polygon_nodes );
4228               if ( !f ||
4229                    nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + nextShift ))
4230               {
4231                 if ( !vTool.IsForward() )
4232                   std::reverse( polygon_nodes.begin(), polygon_nodes.end());
4233                 if ( f )
4234                   aMesh->ChangeElementNodes( f, &polygon_nodes[0], nbn );
4235                 else
4236                   AddElement(polygon_nodes, SMDSAbs_Face, polygon_nodes.size()>4);
4237               }
4238             }
4239
4240             while ( srcElements.Length() < myLastCreatedElems.Length() )
4241               srcElements.Append( *srcEdge );
4242
4243           }  // loop on free faces
4244
4245           // go to the next volume
4246           iVol = 0;
4247           while ( iVol++ < nbVolumesByStep ) v++;
4248
4249         } // loop on steps
4250       } // loop on volumes of one step
4251     } // sweep free links into faces
4252
4253     // Make a ceiling face with a normal external to a volume
4254
4255     SMDS_VolumeTool lastVol( itElem->second.back(), /*ignoreCentralNodes=*/false );
4256
4257     int iF = lastVol.GetFaceIndex( aFaceLastNodes );
4258     if ( iF >= 0 ) {
4259       lastVol.SetExternalNormal();
4260       const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF );
4261       int nbn = lastVol.NbFaceNodes( iF );
4262       if ( nbn == 3 ) {
4263         if (!hasFreeLinks ||
4264             !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]))
4265           myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
4266       }
4267       else if ( nbn == 4 )
4268       {
4269         if (!hasFreeLinks ||
4270             !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]))
4271           myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]));
4272       }
4273       else if ( nbn == 6 && isQuadratic )
4274       {
4275         if (!hasFreeLinks ||
4276             !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[1], nodes[3], nodes[5]) )
4277           myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
4278                                                    nodes[1], nodes[3], nodes[5]));
4279       }
4280       else if ( nbn == 8 && isQuadratic )
4281       {
4282         if (!hasFreeLinks ||
4283             !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[6],
4284                              nodes[1], nodes[3], nodes[5], nodes[7]) )
4285           myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4286                                                    nodes[1], nodes[3], nodes[5], nodes[7]));
4287       }
4288       else if ( nbn == 9 && isQuadratic )
4289       {
4290         if (!hasFreeLinks ||
4291             !aMesh->FindElement(vector<const SMDS_MeshNode*>( nodes, nodes+nbn ),
4292                                 SMDSAbs_Face, /*noMedium=*/false) )
4293           myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4294                                                    nodes[1], nodes[3], nodes[5], nodes[7],
4295                                                    nodes[8]));
4296       }
4297       else {
4298         vector<const SMDS_MeshNode*> polygon_nodes ( nodes, nodes + nbn );
4299         if (!hasFreeLinks || !aMesh->FindFace(polygon_nodes))
4300           myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
4301       }
4302
4303       while ( srcElements.Length() < myLastCreatedElems.Length() )
4304         srcElements.Append( myLastCreatedElems.Last() );
4305     }
4306   } // loop on swept elements
4307 }
4308
4309 //=======================================================================
4310 //function : RotationSweep
4311 //purpose  :
4312 //=======================================================================
4313
4314 SMESH_MeshEditor::PGroupIDs
4315 SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems,
4316                                 const gp_Ax1&      theAxis,
4317                                 const double       theAngle,
4318                                 const int          theNbSteps,
4319                                 const double       theTol,
4320                                 const bool         theMakeGroups,
4321                                 const bool         theMakeWalls)
4322 {
4323   myLastCreatedElems.Clear();
4324   myLastCreatedNodes.Clear();
4325
4326   // source elements for each generated one
4327   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4328
4329   MESSAGE( "RotationSweep()");
4330   gp_Trsf aTrsf;
4331   aTrsf.SetRotation( theAxis, theAngle );
4332   gp_Trsf aTrsf2;
4333   aTrsf2.SetRotation( theAxis, theAngle/2. );
4334
4335   gp_Lin aLine( theAxis );
4336   double aSqTol = theTol * theTol;
4337
4338   SMESHDS_Mesh* aMesh = GetMeshDS();
4339
4340   TNodeOfNodeListMap mapNewNodes;
4341   TElemOfVecOfNnlmiMap mapElemNewNodes;
4342   TElemOfElemListMap newElemsMap;
4343
4344   const bool isQuadraticMesh = bool( myMesh->NbEdges(ORDER_QUADRATIC) +
4345                                      myMesh->NbFaces(ORDER_QUADRATIC) +
4346                                      myMesh->NbVolumes(ORDER_QUADRATIC) );
4347   // loop on theElems
4348   TIDSortedElemSet::iterator itElem;
4349   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4350     const SMDS_MeshElement* elem = *itElem;
4351     if ( !elem || elem->GetType() == SMDSAbs_Volume )
4352       continue;
4353     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4354     newNodesItVec.reserve( elem->NbNodes() );
4355
4356     // loop on elem nodes
4357     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4358     while ( itN->more() )
4359     {
4360       // check if a node has been already sweeped
4361       const SMDS_MeshNode* node = cast2Node( itN->next() );
4362
4363       gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4364       double coord[3];
4365       aXYZ.Coord( coord[0], coord[1], coord[2] );
4366       bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4367
4368       TNodeOfNodeListMapItr nIt =
4369         mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4370       list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4371       if ( listNewNodes.empty() )
4372       {
4373         // check if we are to create medium nodes between corner ones
4374         bool needMediumNodes = false;
4375         if ( isQuadraticMesh )
4376         {
4377           SMDS_ElemIteratorPtr it = node->GetInverseElementIterator();
4378           while (it->more() && !needMediumNodes )
4379           {
4380             const SMDS_MeshElement* invElem = it->next();
4381             if ( invElem != elem && !theElems.count( invElem )) continue;
4382             needMediumNodes = ( invElem->IsQuadratic() && !invElem->IsMediumNode(node) );
4383             if ( !needMediumNodes && invElem->GetEntityType() == SMDSEntity_BiQuad_Quadrangle )
4384               needMediumNodes = true;
4385           }
4386         }
4387
4388         // make new nodes
4389         const SMDS_MeshNode * newNode = node;
4390         for ( int i = 0; i < theNbSteps; i++ ) {
4391           if ( !isOnAxis ) {
4392             if ( needMediumNodes )  // create a medium node
4393             {
4394               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4395               newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4396               myLastCreatedNodes.Append(newNode);
4397               srcNodes.Append( node );
4398               listNewNodes.push_back( newNode );
4399               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4400             }
4401             else {
4402               aTrsf.Transforms( coord[0], coord[1], coord[2] );
4403             }
4404             // create a corner node
4405             newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4406             myLastCreatedNodes.Append(newNode);
4407             srcNodes.Append( node );
4408             listNewNodes.push_back( newNode );
4409           }
4410           else {
4411             listNewNodes.push_back( newNode );
4412             // if ( needMediumNodes )
4413             //   listNewNodes.push_back( newNode );
4414           }
4415         }
4416       }
4417       newNodesItVec.push_back( nIt );
4418     }
4419     // make new elements
4420     sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems );
4421   }
4422
4423   if ( theMakeWalls )
4424     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, theNbSteps, srcElems );
4425
4426   PGroupIDs newGroupIDs;
4427   if ( theMakeGroups )
4428     newGroupIDs = generateGroups( srcNodes, srcElems, "rotated");
4429
4430   return newGroupIDs;
4431 }
4432
4433
4434 //=======================================================================
4435 //function : CreateNode
4436 //purpose  :
4437 //=======================================================================
4438 const SMDS_MeshNode* SMESH_MeshEditor::CreateNode(const double x,
4439                                                   const double y,
4440                                                   const double z,
4441                                                   const double tolnode,
4442                                                   SMESH_SequenceOfNode& aNodes)
4443 {
4444   // myLastCreatedElems.Clear();
4445   // myLastCreatedNodes.Clear();
4446
4447   gp_Pnt P1(x,y,z);
4448   SMESHDS_Mesh * aMesh = myMesh->GetMeshDS();
4449
4450   // try to search in sequence of existing nodes
4451   // if aNodes.Length()>0 we 'nave to use given sequence
4452   // else - use all nodes of mesh
4453   if(aNodes.Length()>0) {
4454     int i;
4455     for(i=1; i<=aNodes.Length(); i++) {
4456       gp_Pnt P2(aNodes.Value(i)->X(),aNodes.Value(i)->Y(),aNodes.Value(i)->Z());
4457       if(P1.Distance(P2)<tolnode)
4458         return aNodes.Value(i);
4459     }
4460   }
4461   else {
4462     SMDS_NodeIteratorPtr itn = aMesh->nodesIterator();
4463     while(itn->more()) {
4464       const SMDS_MeshNode* aN = static_cast<const SMDS_MeshNode*> (itn->next());
4465       gp_Pnt P2(aN->X(),aN->Y(),aN->Z());
4466       if(P1.Distance(P2)<tolnode)
4467         return aN;
4468     }
4469   }
4470
4471   // create new node and return it
4472   const SMDS_MeshNode* NewNode = aMesh->AddNode(x,y,z);
4473   //myLastCreatedNodes.Append(NewNode);
4474   return NewNode;
4475 }
4476
4477
4478 //=======================================================================
4479 //function : ExtrusionSweep
4480 //purpose  :
4481 //=======================================================================
4482
4483 SMESH_MeshEditor::PGroupIDs
4484 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
4485                                   const gp_Vec&       theStep,
4486                                   const int           theNbSteps,
4487                                   TElemOfElemListMap& newElemsMap,
4488                                   const bool          theMakeGroups,
4489                                   const int           theFlags,
4490                                   const double        theTolerance)
4491 {
4492   ExtrusParam aParams;
4493   aParams.myDir = gp_Dir(theStep);
4494   aParams.myNodes.Clear();
4495   aParams.mySteps = new TColStd_HSequenceOfReal;
4496   int i;
4497   for(i=1; i<=theNbSteps; i++)
4498     aParams.mySteps->Append(theStep.Magnitude());
4499
4500   return
4501     ExtrusionSweep(theElems,aParams,newElemsMap,theMakeGroups,theFlags,theTolerance);
4502 }
4503
4504
4505 //=======================================================================
4506 //function : ExtrusionSweep
4507 //purpose  :
4508 //=======================================================================
4509
4510 SMESH_MeshEditor::PGroupIDs
4511 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
4512                                   ExtrusParam&        theParams,
4513                                   TElemOfElemListMap& newElemsMap,
4514                                   const bool          theMakeGroups,
4515                                   const int           theFlags,
4516                                   const double        theTolerance)
4517 {
4518   myLastCreatedElems.Clear();
4519   myLastCreatedNodes.Clear();
4520
4521   // source elements for each generated one
4522   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4523
4524   SMESHDS_Mesh* aMesh = GetMeshDS();
4525
4526   int nbsteps = theParams.mySteps->Length();
4527
4528   TNodeOfNodeListMap mapNewNodes;
4529   //TNodeOfNodeVecMap mapNewNodes;
4530   TElemOfVecOfNnlmiMap mapElemNewNodes;
4531   //TElemOfVecOfMapNodesMap mapElemNewNodes;
4532
4533   const bool isQuadraticMesh = bool( myMesh->NbEdges(ORDER_QUADRATIC) +
4534                                      myMesh->NbFaces(ORDER_QUADRATIC) +
4535                                      myMesh->NbVolumes(ORDER_QUADRATIC) );
4536   // loop on theElems
4537   TIDSortedElemSet::iterator itElem;
4538   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4539     // check element type
4540     const SMDS_MeshElement* elem = *itElem;
4541     if ( !elem  || elem->GetType() == SMDSAbs_Volume )
4542       continue;
4543
4544     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4545     newNodesItVec.reserve( elem->NbNodes() );
4546
4547     // loop on elem nodes
4548     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4549     while ( itN->more() )
4550     {
4551       // check if a node has been already sweeped
4552       const SMDS_MeshNode* node = cast2Node( itN->next() );
4553       TNodeOfNodeListMap::iterator nIt =
4554         mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4555       list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4556       if ( listNewNodes.empty() )
4557       {
4558         // make new nodes
4559
4560         // check if we are to create medium nodes between corner ones
4561         bool needMediumNodes = false;
4562         if ( isQuadraticMesh )
4563         {
4564           SMDS_ElemIteratorPtr it = node->GetInverseElementIterator();
4565           while (it->more() && !needMediumNodes )
4566           {
4567             const SMDS_MeshElement* invElem = it->next();
4568             if ( invElem != elem && !theElems.count( invElem )) continue;
4569             needMediumNodes = ( invElem->IsQuadratic() && !invElem->IsMediumNode(node) );
4570             if ( !needMediumNodes && invElem->GetEntityType() == SMDSEntity_BiQuad_Quadrangle )
4571               needMediumNodes = true;
4572           }
4573         }
4574
4575         double coord[] = { node->X(), node->Y(), node->Z() };
4576         for ( int i = 0; i < nbsteps; i++ )
4577         {
4578           if ( needMediumNodes ) // create a medium node
4579           {
4580             double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1)/2.;
4581             double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1)/2.;
4582             double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1)/2.;
4583             if( theFlags & EXTRUSION_FLAG_SEW ) {
4584               const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4585                                                          theTolerance, theParams.myNodes);
4586               listNewNodes.push_back( newNode );
4587             }
4588             else {
4589               const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4590               myLastCreatedNodes.Append(newNode);
4591               srcNodes.Append( node );
4592               listNewNodes.push_back( newNode );
4593             }
4594           }
4595           // create a corner node
4596           coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4597           coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4598           coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4599           if( theFlags & EXTRUSION_FLAG_SEW ) {
4600             const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4601                                                        theTolerance, theParams.myNodes);
4602             listNewNodes.push_back( newNode );
4603           }
4604           else {
4605             const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4606             myLastCreatedNodes.Append(newNode);
4607             srcNodes.Append( node );
4608             listNewNodes.push_back( newNode );
4609           }
4610         }
4611       }
4612       newNodesItVec.push_back( nIt );
4613     }
4614     // make new elements
4615     sweepElement( elem, newNodesItVec, newElemsMap[elem], nbsteps, srcElems );
4616   }
4617
4618   if( theFlags & EXTRUSION_FLAG_BOUNDARY ) {
4619     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, nbsteps, srcElems );
4620   }
4621   PGroupIDs newGroupIDs;
4622   if ( theMakeGroups )
4623     newGroupIDs = generateGroups( srcNodes, srcElems, "extruded");
4624
4625   return newGroupIDs;
4626 }
4627
4628 //=======================================================================
4629 //function : ExtrusionAlongTrack
4630 //purpose  :
4631 //=======================================================================
4632 SMESH_MeshEditor::Extrusion_Error
4633 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
4634                                        SMESH_subMesh*       theTrack,
4635                                        const SMDS_MeshNode* theN1,
4636                                        const bool           theHasAngles,
4637                                        list<double>&        theAngles,
4638                                        const bool           theLinearVariation,
4639                                        const bool           theHasRefPoint,
4640                                        const gp_Pnt&        theRefPoint,
4641                                        const bool           theMakeGroups)
4642 {
4643   MESSAGE("ExtrusionAlongTrack");
4644   myLastCreatedElems.Clear();
4645   myLastCreatedNodes.Clear();
4646
4647   int aNbE;
4648   std::list<double> aPrms;
4649   TIDSortedElemSet::iterator itElem;
4650
4651   gp_XYZ aGC;
4652   TopoDS_Edge aTrackEdge;
4653   TopoDS_Vertex aV1, aV2;
4654
4655   SMDS_ElemIteratorPtr aItE;
4656   SMDS_NodeIteratorPtr aItN;
4657   SMDSAbs_ElementType aTypeE;
4658
4659   TNodeOfNodeListMap mapNewNodes;
4660
4661   // 1. Check data
4662   aNbE = theElements.size();
4663   // nothing to do
4664   if ( !aNbE )
4665     return EXTR_NO_ELEMENTS;
4666
4667   // 1.1 Track Pattern
4668   ASSERT( theTrack );
4669
4670   SMESHDS_SubMesh* pSubMeshDS = theTrack->GetSubMeshDS();
4671
4672   aItE = pSubMeshDS->GetElements();
4673   while ( aItE->more() ) {
4674     const SMDS_MeshElement* pE = aItE->next();
4675     aTypeE = pE->GetType();
4676     // Pattern must contain links only
4677     if ( aTypeE != SMDSAbs_Edge )
4678       return EXTR_PATH_NOT_EDGE;
4679   }
4680
4681   list<SMESH_MeshEditor_PathPoint> fullList;
4682
4683   const TopoDS_Shape& aS = theTrack->GetSubShape();
4684   // Sub-shape for the Pattern must be an Edge or Wire
4685   if( aS.ShapeType() == TopAbs_EDGE ) {
4686     aTrackEdge = TopoDS::Edge( aS );
4687     // the Edge must not be degenerated
4688     if ( BRep_Tool::Degenerated( aTrackEdge ) )
4689       return EXTR_BAD_PATH_SHAPE;
4690     TopExp::Vertices( aTrackEdge, aV1, aV2 );
4691     aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4692     const SMDS_MeshNode* aN1 = aItN->next();
4693     aItN = theTrack->GetFather()->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4694     const SMDS_MeshNode* aN2 = aItN->next();
4695     // starting node must be aN1 or aN2
4696     if ( !( aN1 == theN1 || aN2 == theN1 ) )
4697       return EXTR_BAD_STARTING_NODE;
4698     aItN = pSubMeshDS->GetNodes();
4699     while ( aItN->more() ) {
4700       const SMDS_MeshNode* pNode = aItN->next();
4701       const SMDS_EdgePosition* pEPos =
4702         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4703       double aT = pEPos->GetUParameter();
4704       aPrms.push_back( aT );
4705     }
4706     //Extrusion_Error err =
4707     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4708   } else if( aS.ShapeType() == TopAbs_WIRE ) {
4709     list< SMESH_subMesh* > LSM;
4710     TopTools_SequenceOfShape Edges;
4711     SMESH_subMeshIteratorPtr itSM = theTrack->getDependsOnIterator(false,true);
4712     while(itSM->more()) {
4713       SMESH_subMesh* SM = itSM->next();
4714       LSM.push_back(SM);
4715       const TopoDS_Shape& aS = SM->GetSubShape();
4716       Edges.Append(aS);
4717     }
4718     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4719     int startNid = theN1->GetID();
4720     TColStd_MapOfInteger UsedNums;
4721     
4722     int NbEdges = Edges.Length();
4723     int i = 1;
4724     for(; i<=NbEdges; i++) {
4725       int k = 0;
4726       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4727       for(; itLSM!=LSM.end(); itLSM++) {
4728         k++;
4729         if(UsedNums.Contains(k)) continue;
4730         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4731         SMESH_subMesh* locTrack = *itLSM;
4732         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4733         TopExp::Vertices( aTrackEdge, aV1, aV2 );
4734         aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4735         const SMDS_MeshNode* aN1 = aItN->next();
4736         aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4737         const SMDS_MeshNode* aN2 = aItN->next();
4738         // starting node must be aN1 or aN2
4739         if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4740         // 2. Collect parameters on the track edge
4741         aPrms.clear();
4742         aItN = locMeshDS->GetNodes();
4743         while ( aItN->more() ) {
4744           const SMDS_MeshNode* pNode = aItN->next();
4745           const SMDS_EdgePosition* pEPos =
4746             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4747           double aT = pEPos->GetUParameter();
4748           aPrms.push_back( aT );
4749         }
4750         list<SMESH_MeshEditor_PathPoint> LPP;
4751         //Extrusion_Error err =
4752         MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4753         LLPPs.push_back(LPP);
4754         UsedNums.Add(k);
4755         // update startN for search following egde
4756         if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4757         else startNid = aN1->GetID();
4758         break;
4759       }
4760     }
4761     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4762     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4763     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4764     for(; itPP!=firstList.end(); itPP++) {
4765       fullList.push_back( *itPP );
4766     }
4767     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4768     fullList.pop_back();
4769     itLLPP++;
4770     for(; itLLPP!=LLPPs.end(); itLLPP++) {
4771       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4772       itPP = currList.begin();
4773       SMESH_MeshEditor_PathPoint PP2 = currList.front();
4774       gp_Dir D1 = PP1.Tangent();
4775       gp_Dir D2 = PP2.Tangent();
4776       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4777                            (D1.Z()+D2.Z())/2 ) );
4778       PP1.SetTangent(Dnew);
4779       fullList.push_back(PP1);
4780       itPP++;
4781       for(; itPP!=firstList.end(); itPP++) {
4782         fullList.push_back( *itPP );
4783       }
4784       PP1 = fullList.back();
4785       fullList.pop_back();
4786     }
4787     // if wire not closed
4788     fullList.push_back(PP1);
4789     // else ???
4790   }
4791   else {
4792     return EXTR_BAD_PATH_SHAPE;
4793   }
4794
4795   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4796                           theHasRefPoint, theRefPoint, theMakeGroups);
4797 }
4798
4799
4800 //=======================================================================
4801 //function : ExtrusionAlongTrack
4802 //purpose  :
4803 //=======================================================================
4804 SMESH_MeshEditor::Extrusion_Error
4805 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
4806                                        SMESH_Mesh*          theTrack,
4807                                        const SMDS_MeshNode* theN1,
4808                                        const bool           theHasAngles,
4809                                        list<double>&        theAngles,
4810                                        const bool           theLinearVariation,
4811                                        const bool           theHasRefPoint,
4812                                        const gp_Pnt&        theRefPoint,
4813                                        const bool           theMakeGroups)
4814 {
4815   myLastCreatedElems.Clear();
4816   myLastCreatedNodes.Clear();
4817
4818   int aNbE;
4819   std::list<double> aPrms;
4820   TIDSortedElemSet::iterator itElem;
4821
4822   gp_XYZ aGC;
4823   TopoDS_Edge aTrackEdge;
4824   TopoDS_Vertex aV1, aV2;
4825
4826   SMDS_ElemIteratorPtr aItE;
4827   SMDS_NodeIteratorPtr aItN;
4828   SMDSAbs_ElementType aTypeE;
4829
4830   TNodeOfNodeListMap mapNewNodes;
4831
4832   // 1. Check data
4833   aNbE = theElements.size();
4834   // nothing to do
4835   if ( !aNbE )
4836     return EXTR_NO_ELEMENTS;
4837
4838   // 1.1 Track Pattern
4839   ASSERT( theTrack );
4840
4841   SMESHDS_Mesh* pMeshDS = theTrack->GetMeshDS();
4842
4843   aItE = pMeshDS->elementsIterator();
4844   while ( aItE->more() ) {
4845     const SMDS_MeshElement* pE = aItE->next();
4846     aTypeE = pE->GetType();
4847     // Pattern must contain links only
4848     if ( aTypeE != SMDSAbs_Edge )
4849       return EXTR_PATH_NOT_EDGE;
4850   }
4851
4852   list<SMESH_MeshEditor_PathPoint> fullList;
4853
4854   const TopoDS_Shape& aS = theTrack->GetShapeToMesh();
4855
4856   if( aS == SMESH_Mesh::PseudoShape() ) {
4857     //Mesh without shape
4858     const SMDS_MeshNode* currentNode = NULL;
4859     const SMDS_MeshNode* prevNode = theN1;
4860     std::vector<const SMDS_MeshNode*> aNodesList;
4861     aNodesList.push_back(theN1);
4862     int nbEdges = 0, conn=0;
4863     const SMDS_MeshElement* prevElem = NULL;
4864     const SMDS_MeshElement* currentElem = NULL;
4865     int totalNbEdges = theTrack->NbEdges();
4866     SMDS_ElemIteratorPtr nIt;
4867     bool isClosed = false;
4868
4869     //check start node
4870     if( !theTrack->GetMeshDS()->Contains(theN1) ) {
4871       return EXTR_BAD_STARTING_NODE;
4872     }
4873     
4874     conn = nbEdgeConnectivity(theN1);
4875     if(conn > 2)
4876       return EXTR_PATH_NOT_EDGE;
4877
4878     aItE = theN1->GetInverseElementIterator();
4879     prevElem = aItE->next();
4880     currentElem = prevElem;
4881     //Get all nodes
4882     if(totalNbEdges == 1 ) {
4883       nIt = currentElem->nodesIterator();
4884       currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
4885       if(currentNode == prevNode)
4886         currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
4887       aNodesList.push_back(currentNode);
4888     } else { 
4889       nIt = currentElem->nodesIterator();
4890       while( nIt->more() ) {
4891         currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
4892         if(currentNode == prevNode)
4893           currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
4894         aNodesList.push_back(currentNode);
4895         
4896         //case of the closed mesh
4897         if(currentNode == theN1) {
4898           nbEdges++;
4899           isClosed = true;
4900           break;
4901         }
4902
4903         conn = nbEdgeConnectivity(currentNode);
4904         if(conn > 2) {
4905           return EXTR_PATH_NOT_EDGE;    
4906         }else if( conn == 1 && nbEdges > 0 ) {
4907           //End of the path
4908           nbEdges++;
4909           break;
4910         }else {
4911           prevNode = currentNode;
4912           aItE = currentNode->GetInverseElementIterator();
4913           currentElem = aItE->next();
4914           if( currentElem  == prevElem)
4915             currentElem = aItE->next();
4916           nIt = currentElem->nodesIterator();
4917           prevElem = currentElem;
4918           nbEdges++;
4919         }
4920       }
4921     } 
4922     
4923     if(nbEdges != totalNbEdges)
4924       return EXTR_PATH_NOT_EDGE;
4925
4926     TopTools_SequenceOfShape Edges;
4927     double x1,x2,y1,y2,z1,z2;
4928     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4929     int startNid = theN1->GetID();
4930     for(int i = 1; i < aNodesList.size(); i++) {
4931       x1 = aNodesList[i-1]->X();x2 = aNodesList[i]->X();
4932       y1 = aNodesList[i-1]->Y();y2 = aNodesList[i]->Y();
4933       z1 = aNodesList[i-1]->Z();z2 = aNodesList[i]->Z();
4934       TopoDS_Edge e = BRepBuilderAPI_MakeEdge(gp_Pnt(x1,y1,z1),gp_Pnt(x2,y2,z2));  
4935       list<SMESH_MeshEditor_PathPoint> LPP;
4936       aPrms.clear();
4937       MakeEdgePathPoints(aPrms, e, (aNodesList[i-1]->GetID()==startNid), LPP);
4938       LLPPs.push_back(LPP);
4939       if( aNodesList[i-1]->GetID() == startNid ) startNid = aNodesList[i]->GetID();
4940       else startNid = aNodesList[i-1]->GetID();
4941
4942     }
4943
4944     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4945     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4946     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4947     for(; itPP!=firstList.end(); itPP++) {
4948       fullList.push_back( *itPP );
4949     }
4950
4951     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4952     SMESH_MeshEditor_PathPoint PP2;
4953     fullList.pop_back();
4954     itLLPP++;
4955     for(; itLLPP!=LLPPs.end(); itLLPP++) {
4956       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4957       itPP = currList.begin();
4958       PP2 = currList.front();
4959       gp_Dir D1 = PP1.Tangent();
4960       gp_Dir D2 = PP2.Tangent();
4961       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4962                            (D1.Z()+D2.Z())/2 ) );
4963       PP1.SetTangent(Dnew);
4964       fullList.push_back(PP1);
4965       itPP++;
4966       for(; itPP!=currList.end(); itPP++) {
4967         fullList.push_back( *itPP );
4968       }
4969       PP1 = fullList.back();
4970       fullList.pop_back();
4971     }
4972     fullList.push_back(PP1);
4973     
4974   } // Sub-shape for the Pattern must be an Edge or Wire
4975   else if( aS.ShapeType() == TopAbs_EDGE ) {
4976     aTrackEdge = TopoDS::Edge( aS );
4977     // the Edge must not be degenerated
4978     if ( BRep_Tool::Degenerated( aTrackEdge ) )
4979       return EXTR_BAD_PATH_SHAPE;
4980     TopExp::Vertices( aTrackEdge, aV1, aV2 );
4981     aItN = theTrack->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4982     const SMDS_MeshNode* aN1 = aItN->next();
4983     aItN = theTrack->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4984     const SMDS_MeshNode* aN2 = aItN->next();
4985     // starting node must be aN1 or aN2
4986     if ( !( aN1 == theN1 || aN2 == theN1 ) )
4987       return EXTR_BAD_STARTING_NODE;
4988     aItN = pMeshDS->nodesIterator();
4989     while ( aItN->more() ) {
4990       const SMDS_MeshNode* pNode = aItN->next();
4991       if( pNode==aN1 || pNode==aN2 ) continue;
4992       const SMDS_EdgePosition* pEPos =
4993         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4994       double aT = pEPos->GetUParameter();
4995       aPrms.push_back( aT );
4996     }
4997     //Extrusion_Error err =
4998     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4999   }
5000   else if( aS.ShapeType() == TopAbs_WIRE ) {
5001     list< SMESH_subMesh* > LSM;
5002     TopTools_SequenceOfShape Edges;
5003     TopExp_Explorer eExp(aS, TopAbs_EDGE);
5004     for(; eExp.More(); eExp.Next()) {
5005       TopoDS_Edge E = TopoDS::Edge( eExp.Current() );
5006       if( BRep_Tool::Degenerated(E) ) continue;
5007       SMESH_subMesh* SM = theTrack->GetSubMesh(E);
5008       if(SM) {
5009         LSM.push_back(SM);
5010         Edges.Append(E);
5011       }
5012     }
5013     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
5014     int startNid = theN1->GetID();
5015     TColStd_MapOfInteger UsedNums;
5016     int NbEdges = Edges.Length();
5017     int i = 1;
5018     for(; i<=NbEdges; i++) {
5019       int k = 0;
5020       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
5021       for(; itLSM!=LSM.end(); itLSM++) {
5022         k++;
5023         if(UsedNums.Contains(k)) continue;
5024         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
5025         SMESH_subMesh* locTrack = *itLSM;
5026         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
5027         TopExp::Vertices( aTrackEdge, aV1, aV2 );
5028         aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
5029         const SMDS_MeshNode* aN1 = aItN->next();
5030         aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
5031         const SMDS_MeshNode* aN2 = aItN->next();
5032         // starting node must be aN1 or aN2
5033         if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
5034         // 2. Collect parameters on the track edge
5035         aPrms.clear();
5036         aItN = locMeshDS->GetNodes();
5037         while ( aItN->more() ) {
5038           const SMDS_MeshNode* pNode = aItN->next();
5039           const SMDS_EdgePosition* pEPos =
5040             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
5041           double aT = pEPos->GetUParameter();
5042           aPrms.push_back( aT );
5043         }
5044         list<SMESH_MeshEditor_PathPoint> LPP;
5045         //Extrusion_Error err =
5046         MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
5047         LLPPs.push_back(LPP);
5048         UsedNums.Add(k);
5049         // update startN for search following egde
5050         if( aN1->GetID() == startNid ) startNid = aN2->GetID();
5051         else startNid = aN1->GetID();
5052         break;
5053       }
5054     }
5055     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
5056     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
5057     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
5058     for(; itPP!=firstList.end(); itPP++) {
5059       fullList.push_back( *itPP );
5060     }
5061     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
5062     fullList.pop_back();
5063     itLLPP++;
5064     for(; itLLPP!=LLPPs.end(); itLLPP++) {
5065       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
5066       itPP = currList.begin();
5067       SMESH_MeshEditor_PathPoint PP2 = currList.front();
5068       gp_Dir D1 = PP1.Tangent();
5069       gp_Dir D2 = PP2.Tangent();
5070       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
5071                            (D1.Z()+D2.Z())/2 ) );
5072       PP1.SetTangent(Dnew);
5073       fullList.push_back(PP1);
5074       itPP++;
5075       for(; itPP!=currList.end(); itPP++) {
5076         fullList.push_back( *itPP );
5077       }
5078       PP1 = fullList.back();
5079       fullList.pop_back();
5080     }
5081     // if wire not closed
5082     fullList.push_back(PP1);
5083     // else ???
5084   }
5085   else {
5086     return EXTR_BAD_PATH_SHAPE;
5087   }
5088
5089   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
5090                           theHasRefPoint, theRefPoint, theMakeGroups);
5091 }
5092
5093
5094 //=======================================================================
5095 //function : MakeEdgePathPoints
5096 //purpose  : auxilary for ExtrusionAlongTrack
5097 //=======================================================================
5098 SMESH_MeshEditor::Extrusion_Error
5099 SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>& aPrms,
5100                                      const TopoDS_Edge& aTrackEdge,
5101                                      bool FirstIsStart,
5102                                      list<SMESH_MeshEditor_PathPoint>& LPP)
5103 {
5104   Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2;
5105   aTolVec=1.e-7;
5106   aTolVec2=aTolVec*aTolVec;
5107   double aT1, aT2;
5108   TopoDS_Vertex aV1, aV2;
5109   TopExp::Vertices( aTrackEdge, aV1, aV2 );
5110   aT1=BRep_Tool::Parameter( aV1, aTrackEdge );
5111   aT2=BRep_Tool::Parameter( aV2, aTrackEdge );
5112   // 2. Collect parameters on the track edge
5113   aPrms.push_front( aT1 );
5114   aPrms.push_back( aT2 );
5115   // sort parameters
5116   aPrms.sort();
5117   if( FirstIsStart ) {
5118     if ( aT1 > aT2 ) {
5119       aPrms.reverse();
5120     }
5121   }
5122   else {
5123     if ( aT2 > aT1 ) {
5124       aPrms.reverse();
5125     }
5126   }
5127   // 3. Path Points
5128   SMESH_MeshEditor_PathPoint aPP;
5129   Handle(Geom_Curve) aC3D = BRep_Tool::Curve( aTrackEdge, aTx1, aTx2 );
5130   std::list<double>::iterator aItD = aPrms.begin();
5131   for(; aItD != aPrms.end(); ++aItD) {
5132     double aT = *aItD;
5133     gp_Pnt aP3D;
5134     gp_Vec aVec;
5135     aC3D->D1( aT, aP3D, aVec );
5136     aL2 = aVec.SquareMagnitude();
5137     if ( aL2 < aTolVec2 )
5138       return EXTR_CANT_GET_TANGENT;
5139     gp_Dir aTgt( aVec );
5140     aPP.SetPnt( aP3D );
5141     aPP.SetTangent( aTgt );
5142     aPP.SetParameter( aT );
5143     LPP.push_back(aPP);
5144   }
5145   return EXTR_OK;
5146 }
5147
5148
5149 //=======================================================================
5150 //function : MakeExtrElements
5151 //purpose  : auxilary for ExtrusionAlongTrack
5152 //=======================================================================
5153 SMESH_MeshEditor::Extrusion_Error
5154 SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet&  theElements,
5155                                    list<SMESH_MeshEditor_PathPoint>& fullList,
5156                                    const bool theHasAngles,
5157                                    list<double>& theAngles,
5158                                    const bool theLinearVariation,
5159                                    const bool theHasRefPoint,
5160                                    const gp_Pnt& theRefPoint,
5161                                    const bool theMakeGroups)
5162 {
5163   MESSAGE("MakeExtrElements");
5164   //cout<<"MakeExtrElements  fullList.size() = "<<fullList.size()<<endl;
5165   int aNbTP = fullList.size();
5166   vector<SMESH_MeshEditor_PathPoint> aPPs(aNbTP);
5167   // Angles
5168   if( theHasAngles && theAngles.size()>0 && theLinearVariation ) {
5169     LinearAngleVariation(aNbTP-1, theAngles);
5170   }
5171   vector<double> aAngles( aNbTP );
5172   int j = 0;
5173   for(; j<aNbTP; ++j) {
5174     aAngles[j] = 0.;
5175   }
5176   if ( theHasAngles ) {
5177     double anAngle;;
5178     std::list<double>::iterator aItD = theAngles.begin();
5179     for ( j=1; (aItD != theAngles.end()) && (j<aNbTP); ++aItD, ++j ) {
5180       anAngle = *aItD;
5181       aAngles[j] = anAngle;
5182     }
5183   }
5184   // fill vector of path points with angles
5185   //aPPs.resize(fullList.size());
5186   j = -1;
5187   list<SMESH_MeshEditor_PathPoint>::iterator itPP = fullList.begin();
5188   for(; itPP!=fullList.end(); itPP++) {
5189     j++;
5190     SMESH_MeshEditor_PathPoint PP = *itPP;
5191     PP.SetAngle(aAngles[j]);
5192     aPPs[j] = PP;
5193   }
5194
5195   TNodeOfNodeListMap mapNewNodes;
5196   TElemOfVecOfNnlmiMap mapElemNewNodes;
5197   TElemOfElemListMap newElemsMap;
5198   TIDSortedElemSet::iterator itElem;
5199   double aX, aY, aZ;
5200   int aNb;
5201   SMDSAbs_ElementType aTypeE;
5202   // source elements for each generated one
5203   SMESH_SequenceOfElemPtr srcElems, srcNodes;
5204
5205   // 3. Center of rotation aV0
5206   gp_Pnt aV0 = theRefPoint;
5207   gp_XYZ aGC;
5208   if ( !theHasRefPoint ) {
5209     aNb = 0;
5210     aGC.SetCoord( 0.,0.,0. );
5211
5212     itElem = theElements.begin();
5213     for ( ; itElem != theElements.end(); itElem++ ) {
5214       const SMDS_MeshElement* elem = *itElem;
5215
5216       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5217       while ( itN->more() ) {
5218         const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( itN->next() );
5219         aX = node->X();
5220         aY = node->Y();
5221         aZ = node->Z();
5222
5223         if ( mapNewNodes.find( node ) == mapNewNodes.end() ) {
5224           list<const SMDS_MeshNode*> aLNx;
5225           mapNewNodes[node] = aLNx;
5226           //
5227           gp_XYZ aXYZ( aX, aY, aZ );
5228           aGC += aXYZ;
5229           ++aNb;
5230         }
5231       }
5232     }
5233     aGC /= aNb;
5234     aV0.SetXYZ( aGC );
5235   } // if (!theHasRefPoint) {
5236   mapNewNodes.clear();
5237
5238   // 4. Processing the elements
5239   SMESHDS_Mesh* aMesh = GetMeshDS();
5240
5241   for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) {
5242     // check element type
5243     const SMDS_MeshElement* elem = *itElem;
5244     aTypeE = elem->GetType();
5245     if ( !elem || ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) )
5246       continue;
5247
5248     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
5249     newNodesItVec.reserve( elem->NbNodes() );
5250
5251     // loop on elem nodes
5252     int nodeIndex = -1;
5253     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5254     while ( itN->more() )
5255     {
5256       ++nodeIndex;
5257       // check if a node has been already processed
5258       const SMDS_MeshNode* node =
5259         static_cast<const SMDS_MeshNode*>( itN->next() );
5260       TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
5261       if ( nIt == mapNewNodes.end() ) {
5262         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
5263         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
5264
5265         // make new nodes
5266         aX = node->X();  aY = node->Y(); aZ = node->Z();
5267
5268         Standard_Real aAngle1x, aAngleT1T0, aTolAng;
5269         gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
5270         gp_Ax1 anAx1, anAxT1T0;
5271         gp_Dir aDT1x, aDT0x, aDT1T0;
5272
5273         aTolAng=1.e-4;
5274
5275         aV0x = aV0;
5276         aPN0.SetCoord(aX, aY, aZ);
5277
5278         const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
5279         aP0x = aPP0.Pnt();
5280         aDT0x= aPP0.Tangent();
5281         //cout<<"j = 0   PP: Pnt("<<aP0x.X()<<","<<aP0x.Y()<<","<<aP0x.Z()<<")"<<endl;
5282
5283         for ( j = 1; j < aNbTP; ++j ) {
5284           const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
5285           aP1x = aPP1.Pnt();
5286           aDT1x = aPP1.Tangent();
5287           aAngle1x = aPP1.Angle();
5288
5289           gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
5290           // Translation
5291           gp_Vec aV01x( aP0x, aP1x );
5292           aTrsf.SetTranslation( aV01x );
5293
5294           // traslated point
5295           aV1x = aV0x.Transformed( aTrsf );
5296           aPN1 = aPN0.Transformed( aTrsf );
5297
5298           // rotation 1 [ T1,T0 ]
5299           aAngleT1T0=-aDT1x.Angle( aDT0x );
5300           if (fabs(aAngleT1T0) > aTolAng) {
5301             aDT1T0=aDT1x^aDT0x;
5302             anAxT1T0.SetLocation( aV1x );
5303             anAxT1T0.SetDirection( aDT1T0 );
5304             aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 );
5305
5306             aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
5307           }
5308
5309           // rotation 2
5310           if ( theHasAngles ) {
5311             anAx1.SetLocation( aV1x );
5312             anAx1.SetDirection( aDT1x );
5313             aTrsfRot.SetRotation( anAx1, aAngle1x );
5314
5315             aPN1 = aPN1.Transformed( aTrsfRot );
5316           }
5317
5318           // make new node
5319           //MESSAGE("elem->IsQuadratic " << elem->IsQuadratic() << " " << elem->IsMediumNode(node));
5320           if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5321             // create additional node
5322             double x = ( aPN1.X() + aPN0.X() )/2.;
5323             double y = ( aPN1.Y() + aPN0.Y() )/2.;
5324             double z = ( aPN1.Z() + aPN0.Z() )/2.;
5325             const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z);
5326             myLastCreatedNodes.Append(newNode);
5327             srcNodes.Append( node );
5328             listNewNodes.push_back( newNode );
5329           }
5330           aX = aPN1.X();
5331           aY = aPN1.Y();
5332           aZ = aPN1.Z();
5333           const SMDS_MeshNode* newNode = aMesh->AddNode( aX, aY, aZ );
5334           myLastCreatedNodes.Append(newNode);
5335           srcNodes.Append( node );
5336           listNewNodes.push_back( newNode );
5337
5338           aPN0 = aPN1;
5339           aP0x = aP1x;
5340           aV0x = aV1x;
5341           aDT0x = aDT1x;
5342         }
5343       }
5344
5345       else {
5346         // if current elem is quadratic and current node is not medium
5347         // we have to check - may be it is needed to insert additional nodes
5348         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5349           list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
5350           if(listNewNodes.size()==aNbTP-1) {
5351             vector<const SMDS_MeshNode*> aNodes(2*(aNbTP-1));
5352             gp_XYZ P(node->X(), node->Y(), node->Z());
5353             list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin();
5354             int i;
5355             for(i=0; i<aNbTP-1; i++) {
5356               const SMDS_MeshNode* N = *it;
5357               double x = ( N->X() + P.X() )/2.;
5358               double y = ( N->Y() + P.Y() )/2.;
5359               double z = ( N->Z() + P.Z() )/2.;
5360               const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z);
5361               srcNodes.Append( node );
5362               myLastCreatedNodes.Append(newN);
5363               aNodes[2*i] = newN;
5364               aNodes[2*i+1] = N;
5365               P = gp_XYZ(N->X(),N->Y(),N->Z());
5366             }
5367             listNewNodes.clear();
5368             for(i=0; i<2*(aNbTP-1); i++) {
5369               listNewNodes.push_back(aNodes[i]);
5370             }
5371           }
5372         }
5373       }
5374
5375       newNodesItVec.push_back( nIt );
5376     }
5377     // make new elements
5378     //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem],
5379     //              newNodesItVec[0]->second.size(), myLastCreatedElems );
5380     sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems );
5381   }
5382
5383   makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElements, aNbTP-1, srcElems );
5384
5385   if ( theMakeGroups )
5386     generateGroups( srcNodes, srcElems, "extruded");
5387
5388   return EXTR_OK;
5389 }
5390
5391
5392 //=======================================================================
5393 //function : LinearAngleVariation
5394 //purpose  : auxilary for ExtrusionAlongTrack
5395 //=======================================================================
5396 void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps,
5397                                             list<double>& Angles)
5398 {
5399   int nbAngles = Angles.size();
5400   if( nbSteps > nbAngles ) {
5401     vector<double> theAngles(nbAngles);
5402     list<double>::iterator it = Angles.begin();
5403     int i = -1;
5404     for(; it!=Angles.end(); it++) {
5405       i++;
5406       theAngles[i] = (*it);
5407     }
5408     list<double> res;
5409     double rAn2St = double( nbAngles ) / double( nbSteps );
5410     double angPrev = 0, angle;
5411     for ( int iSt = 0; iSt < nbSteps; ++iSt ) {
5412       double angCur = rAn2St * ( iSt+1 );
5413       double angCurFloor  = floor( angCur );
5414       double angPrevFloor = floor( angPrev );
5415       if ( angPrevFloor == angCurFloor )
5416         angle = rAn2St * theAngles[ int( angCurFloor ) ];
5417       else {
5418         int iP = int( angPrevFloor );
5419         double angPrevCeil = ceil(angPrev);
5420         angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
5421
5422         int iC = int( angCurFloor );
5423         if ( iC < nbAngles )
5424           angle += ( angCur - angCurFloor ) * theAngles[ iC ];
5425
5426         iP = int( angPrevCeil );
5427         while ( iC-- > iP )
5428           angle += theAngles[ iC ];
5429       }
5430       res.push_back(angle);
5431       angPrev = angCur;
5432     }
5433     Angles.clear();
5434     it = res.begin();
5435     for(; it!=res.end(); it++)
5436       Angles.push_back( *it );
5437   }
5438 }
5439
5440
5441 //================================================================================
5442 /*!
5443  * \brief Move or copy theElements applying theTrsf to their nodes
5444  *  \param theElems - elements to transform, if theElems is empty then apply to all mesh nodes
5445  *  \param theTrsf - transformation to apply
5446  *  \param theCopy - if true, create translated copies of theElems
5447  *  \param theMakeGroups - if true and theCopy, create translated groups
5448  *  \param theTargetMesh - mesh to copy translated elements into
5449  *  \return SMESH_MeshEditor::PGroupIDs - list of ids of created groups
5450  */
5451 //================================================================================
5452
5453 SMESH_MeshEditor::PGroupIDs
5454 SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
5455                              const gp_Trsf&     theTrsf,
5456                              const bool         theCopy,
5457                              const bool         theMakeGroups,
5458                              SMESH_Mesh*        theTargetMesh)
5459 {
5460   myLastCreatedElems.Clear();
5461   myLastCreatedNodes.Clear();
5462
5463   bool needReverse = false;
5464   string groupPostfix;
5465   switch ( theTrsf.Form() ) {
5466   case gp_PntMirror:
5467     MESSAGE("gp_PntMirror");
5468     needReverse = true;
5469     groupPostfix = "mirrored";
5470     break;
5471   case gp_Ax1Mirror:
5472     MESSAGE("gp_Ax1Mirror");
5473     groupPostfix = "mirrored";
5474     break;
5475   case gp_Ax2Mirror:
5476     MESSAGE("gp_Ax2Mirror");
5477     needReverse = true;
5478     groupPostfix = "mirrored";
5479     break;
5480   case gp_Rotation:
5481     MESSAGE("gp_Rotation");
5482     groupPostfix = "rotated";
5483     break;
5484   case gp_Translation:
5485     MESSAGE("gp_Translation");
5486     groupPostfix = "translated";
5487     break;
5488   case gp_Scale:
5489     MESSAGE("gp_Scale");
5490     groupPostfix = "scaled";
5491     break;
5492   case gp_CompoundTrsf: // different scale by axis
5493     MESSAGE("gp_CompoundTrsf");
5494     groupPostfix = "scaled";
5495     break;
5496   default:
5497     MESSAGE("default");
5498     needReverse = false;
5499     groupPostfix = "transformed";
5500   }
5501
5502   SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5503   SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5504   SMESHDS_Mesh* aMesh    = GetMeshDS();
5505
5506
5507   // map old node to new one
5508   TNodeNodeMap nodeMap;
5509
5510   // elements sharing moved nodes; those of them which have all
5511   // nodes mirrored but are not in theElems are to be reversed
5512   TIDSortedElemSet inverseElemSet;
5513
5514   // source elements for each generated one
5515   SMESH_SequenceOfElemPtr srcElems, srcNodes;
5516
5517   // issue 021015: EDF 1578 SMESH: Free nodes are removed when translating a mesh
5518   TIDSortedElemSet orphanNode;
5519
5520   if ( theElems.empty() ) // transform the whole mesh
5521   {
5522     // add all elements
5523     SMDS_ElemIteratorPtr eIt = aMesh->elementsIterator();
5524     while ( eIt->more() ) theElems.insert( eIt->next() );
5525     // add orphan nodes
5526     SMDS_NodeIteratorPtr nIt = aMesh->nodesIterator();
5527     while ( nIt->more() )
5528     {
5529       const SMDS_MeshNode* node = nIt->next();
5530       if ( node->NbInverseElements() == 0)
5531         orphanNode.insert( node );
5532     }
5533   }
5534
5535   // loop on elements to transform nodes : first orphan nodes then elems
5536   TIDSortedElemSet::iterator itElem;
5537   TIDSortedElemSet *elements[] = {&orphanNode, &theElems };
5538   for (int i=0; i<2; i++)
5539   for ( itElem = elements[i]->begin(); itElem != elements[i]->end(); itElem++ ) {
5540     const SMDS_MeshElement* elem = *itElem;
5541     if ( !elem )
5542       continue;
5543
5544     // loop on elem nodes
5545     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5546     while ( itN->more() ) {
5547
5548       const SMDS_MeshNode* node = cast2Node( itN->next() );
5549       // check if a node has been already transformed
5550       pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5551         nodeMap.insert( make_pair ( node, node ));
5552       if ( !n2n_isnew.second )
5553         continue;
5554
5555       double coord[3];
5556       coord[0] = node->X();
5557       coord[1] = node->Y();
5558       coord[2] = node->Z();
5559       theTrsf.Transforms( coord[0], coord[1], coord[2] );
5560       if ( theTargetMesh ) {
5561         const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5562         n2n_isnew.first->second = newNode;
5563         myLastCreatedNodes.Append(newNode);
5564         srcNodes.Append( node );
5565       }
5566       else if ( theCopy ) {
5567         const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5568         n2n_isnew.first->second = newNode;
5569         myLastCreatedNodes.Append(newNode);
5570         srcNodes.Append( node );
5571       }
5572       else {
5573         aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5574         // node position on shape becomes invalid
5575         const_cast< SMDS_MeshNode* > ( node )->SetPosition
5576           ( SMDS_SpacePosition::originSpacePosition() );
5577       }
5578
5579       // keep inverse elements
5580       if ( !theCopy && !theTargetMesh && needReverse ) {
5581         SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5582         while ( invElemIt->more() ) {
5583           const SMDS_MeshElement* iel = invElemIt->next();
5584           inverseElemSet.insert( iel );
5585         }
5586       }
5587     }
5588   }
5589
5590   // either create new elements or reverse mirrored ones
5591   if ( !theCopy && !needReverse && !theTargetMesh )
5592     return PGroupIDs();
5593
5594   TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5595   for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5596     theElems.insert( *invElemIt );
5597
5598   // Replicate or reverse elements
5599
5600   std::vector<int> iForw;
5601   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5602   {
5603     const SMDS_MeshElement* elem = *itElem;
5604     if ( !elem || elem->GetType() == SMDSAbs_Node )
5605       continue;
5606
5607     int nbNodes = elem->NbNodes();
5608     int elemType = elem->GetType();
5609
5610     if (elem->IsPoly()) {
5611
5612       // polygon or polyhedral volume
5613       switch ( elemType ) {
5614       case SMDSAbs_Face:
5615         {
5616           vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5617           int iNode = 0;
5618           SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5619           while (itN->more()) {
5620             const SMDS_MeshNode* node =
5621               static_cast<const SMDS_MeshNode*>(itN->next());
5622             TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5623             if (nodeMapIt == nodeMap.end())
5624               break; // not all nodes transformed
5625             if (needReverse) {
5626               // reverse mirrored faces and volumes
5627               poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5628             } else {
5629               poly_nodes[iNode] = (*nodeMapIt).second;
5630             }
5631             iNode++;
5632           }
5633           if ( iNode != nbNodes )
5634             continue; // not all nodes transformed
5635
5636           if ( theTargetMesh ) {
5637             myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5638             srcElems.Append( elem );
5639           }
5640           else if ( theCopy ) {
5641             myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5642             srcElems.Append( elem );
5643           }
5644           else {
5645             aMesh->ChangePolygonNodes(elem, poly_nodes);
5646           }
5647         }
5648         break;
5649       case SMDSAbs_Volume:
5650         {
5651           const SMDS_VtkVolume* aPolyedre =
5652             dynamic_cast<const SMDS_VtkVolume*>( elem );
5653           if (!aPolyedre) {
5654             MESSAGE("Warning: bad volumic element");
5655             continue;
5656           }
5657
5658           vector<const SMDS_MeshNode*> poly_nodes; poly_nodes.reserve( nbNodes );
5659           vector<int> quantities;
5660
5661           bool allTransformed = true;
5662           int nbFaces = aPolyedre->NbFaces();
5663           for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5664             int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5665             for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5666               const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5667               TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5668               if (nodeMapIt == nodeMap.end()) {
5669                 allTransformed = false; // not all nodes transformed
5670               } else {
5671                 poly_nodes.push_back((*nodeMapIt).second);
5672               }
5673               if ( needReverse && allTransformed )
5674                 std::reverse( poly_nodes.end() - nbFaceNodes, poly_nodes.end() );
5675             }
5676             quantities.push_back(nbFaceNodes);
5677           }
5678           if ( !allTransformed )
5679             continue; // not all nodes transformed
5680
5681           if ( theTargetMesh ) {
5682             myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5683             srcElems.Append( elem );
5684           }
5685           else if ( theCopy ) {
5686             myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5687             srcElems.Append( elem );
5688           }
5689           else {
5690             aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5691           }
5692         }
5693         break;
5694       default:;
5695       }
5696       continue;
5697
5698     } // elem->isPoly()
5699
5700     // Regular elements
5701
5702     while ( iForw.size() < nbNodes ) iForw.push_back( iForw.size() );
5703     const std::vector<int>& iRev = SMDS_MeshCell::reverseSmdsOrder( elem->GetEntityType() );
5704     const std::vector<int>& i = needReverse ? iRev : iForw;
5705
5706     // find transformed nodes
5707     vector<const SMDS_MeshNode*> nodes(nbNodes);
5708     int iNode = 0;
5709     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5710     while ( itN->more() ) {
5711       const SMDS_MeshNode* node =
5712         static_cast<const SMDS_MeshNode*>( itN->next() );
5713       TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5714       if ( nodeMapIt == nodeMap.end() )
5715         break; // not all nodes transformed
5716       nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5717     }
5718     if ( iNode != nbNodes )
5719       continue; // not all nodes transformed
5720
5721     if ( theTargetMesh ) {
5722       if ( SMDS_MeshElement* copy =
5723            targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5724         myLastCreatedElems.Append( copy );
5725         srcElems.Append( elem );
5726       }
5727     }
5728     else if ( theCopy ) {
5729       if ( AddElement( nodes, elem->GetType(), elem->IsPoly() ))
5730         srcElems.Append( elem );
5731     }
5732     else {
5733       // reverse element as it was reversed by transformation
5734       if ( nbNodes > 2 )
5735         aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5736     }
5737
5738   } // loop on elements
5739
5740   PGroupIDs newGroupIDs;
5741
5742   if ( ( theMakeGroups && theCopy ) ||
5743        ( theMakeGroups && theTargetMesh ) )
5744     newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5745
5746   return newGroupIDs;
5747 }
5748
5749 //=======================================================================
5750 /*!
5751  * \brief Create groups of elements made during transformation
5752  * \param nodeGens - nodes making corresponding myLastCreatedNodes
5753  * \param elemGens - elements making corresponding myLastCreatedElems
5754  * \param postfix - to append to names of new groups
5755  */
5756 //=======================================================================
5757
5758 SMESH_MeshEditor::PGroupIDs
5759 SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
5760                                  const SMESH_SequenceOfElemPtr& elemGens,
5761                                  const std::string&             postfix,
5762                                  SMESH_Mesh*                    targetMesh)
5763 {
5764   PGroupIDs newGroupIDs( new list<int> );
5765   SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh();
5766
5767   // Sort existing groups by types and collect their names
5768
5769   // to store an old group and a generated new one
5770   typedef pair< SMESHDS_GroupBase*, SMDS_MeshGroup* > TOldNewGroup;
5771   vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
5772   // group names
5773   set< string > groupNames;
5774   //
5775   SMDS_MeshGroup* nullNewGroup = (SMDS_MeshGroup*) 0;
5776   SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups();
5777   while ( groupIt->more() ) {
5778     SMESH_Group * group = groupIt->next();
5779     if ( !group ) continue;
5780     SMESHDS_GroupBase* groupDS = group->GetGroupDS();
5781     if ( !groupDS || groupDS->IsEmpty() ) continue;
5782     groupNames.insert( group->GetName() );
5783     groupDS->SetStoreName( group->GetName() );
5784     groupsByType[ groupDS->GetType() ].push_back( make_pair( groupDS, nullNewGroup ));
5785   }
5786
5787   // Groups creation
5788
5789   // loop on nodes and elements
5790   for ( int isNodes = 0; isNodes < 2; ++isNodes )
5791   {
5792     const SMESH_SequenceOfElemPtr& gens  = isNodes ? nodeGens : elemGens;
5793     const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
5794     if ( gens.Length() != elems.Length() )
5795       throw SALOME_Exception(LOCALIZED("invalid args"));
5796
5797     // loop on created elements
5798     for (int iElem = 1; iElem <= elems.Length(); ++iElem )
5799     {
5800       const SMDS_MeshElement* sourceElem = gens( iElem );
5801       if ( !sourceElem ) {
5802         MESSAGE("generateGroups(): NULL source element");
5803         continue;
5804       }
5805       list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
5806       if ( groupsOldNew.empty() ) {
5807         while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
5808           ++iElem; // skip all elements made by sourceElem
5809         continue;
5810       }
5811       // collect all elements made by sourceElem
5812       list< const SMDS_MeshElement* > resultElems;
5813       if ( const SMDS_MeshElement* resElem = elems( iElem ))
5814         if ( resElem != sourceElem )
5815           resultElems.push_back( resElem );
5816       while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
5817         if ( const SMDS_MeshElement* resElem = elems( ++iElem ))
5818           if ( resElem != sourceElem )
5819             resultElems.push_back( resElem );
5820       // do not generate element groups from node ones
5821 //      if ( sourceElem->GetType() == SMDSAbs_Node &&
5822 //           elems( iElem )->GetType() != SMDSAbs_Node )
5823 //        continue;
5824
5825       // add resultElems to groups made by ones the sourceElem belongs to
5826       list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
5827       for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
5828       {
5829         SMESHDS_GroupBase* oldGroup = gOldNew->first;
5830         if ( oldGroup->Contains( sourceElem )) // sourceElem in oldGroup
5831         {
5832           SMDS_MeshGroup* & newGroup = gOldNew->second;
5833           if ( !newGroup )// create a new group
5834           {
5835             // make a name
5836             string name = oldGroup->GetStoreName();
5837             if ( !targetMesh ) {
5838               name += "_";
5839               name += postfix;
5840               int nb = 0;
5841               while ( !groupNames.insert( name ).second ) // name exists
5842               {
5843                 if ( nb == 0 ) {
5844                   name += "_1";
5845                 }
5846                 else {
5847                   TCollection_AsciiString nbStr(nb+1);
5848                   name.resize( name.rfind('_')+1 );
5849                   name += nbStr.ToCString();
5850                 }
5851                 ++nb;
5852               }
5853             }
5854             // make a group
5855             int id;
5856             SMESH_Group* group = mesh->AddGroup( resultElems.back()->GetType(),
5857                                                  name.c_str(), id );
5858             SMESHDS_Group* groupDS = static_cast<SMESHDS_Group*>(group->GetGroupDS());
5859             newGroup = & groupDS->SMDSGroup();
5860             newGroupIDs->push_back( id );
5861           }
5862
5863           // fill in a new group
5864           list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
5865           for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
5866             newGroup->Add( *resElemIt );
5867         }
5868       }
5869     } // loop on created elements
5870   }// loop on nodes and elements
5871
5872   return newGroupIDs;
5873 }
5874
5875 //================================================================================
5876 /*!
5877  * \brief Return list of group of nodes close to each other within theTolerance
5878  *        Search among theNodes or in the whole mesh if theNodes is empty using
5879  *        an Octree algorithm
5880  */
5881 //================================================================================
5882
5883 void SMESH_MeshEditor::FindCoincidentNodes (TIDSortedNodeSet &   theNodes,
5884                                             const double         theTolerance,
5885                                             TListOfListOfNodes & theGroupsOfNodes)
5886 {
5887   myLastCreatedElems.Clear();
5888   myLastCreatedNodes.Clear();
5889
5890   if ( theNodes.empty() )
5891   { // get all nodes in the mesh
5892     SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator(/*idInceasingOrder=*/true);
5893     while ( nIt->more() )
5894       theNodes.insert( theNodes.end(),nIt->next());
5895   }
5896
5897   SMESH_OctreeNode::FindCoincidentNodes ( theNodes, &theGroupsOfNodes, theTolerance);
5898 }
5899
5900
5901 //=======================================================================
5902 /*!
5903  * \brief Implementation of search for the node closest to point
5904  */
5905 //=======================================================================
5906
5907 struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
5908 {
5909   //---------------------------------------------------------------------
5910   /*!
5911    * \brief Constructor
5912    */
5913   SMESH_NodeSearcherImpl( const SMESHDS_Mesh* theMesh )
5914   {
5915     myMesh = ( SMESHDS_Mesh* ) theMesh;
5916
5917     TIDSortedNodeSet nodes;
5918     if ( theMesh ) {
5919       SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator(/*idInceasingOrder=*/true);
5920       while ( nIt->more() )
5921         nodes.insert( nodes.end(), nIt->next() );
5922     }
5923     myOctreeNode = new SMESH_OctreeNode(nodes) ;
5924
5925     // get max size of a leaf box
5926     SMESH_OctreeNode* tree = myOctreeNode;
5927     while ( !tree->isLeaf() )
5928     {
5929       SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
5930       if ( cIt->more() )
5931         tree = cIt->next();
5932     }
5933     myHalfLeafSize = tree->maxSize() / 2.;
5934   }
5935
5936   //---------------------------------------------------------------------
5937   /*!
5938    * \brief Move node and update myOctreeNode accordingly
5939    */
5940   void MoveNode( const SMDS_MeshNode* node, const gp_Pnt& toPnt )
5941   {
5942     myOctreeNode->UpdateByMoveNode( node, toPnt );
5943     myMesh->MoveNode( node, toPnt.X(), toPnt.Y(), toPnt.Z() );
5944   }
5945
5946   //---------------------------------------------------------------------
5947   /*!
5948    * \brief Do it's job
5949    */
5950   const SMDS_MeshNode* FindClosestTo( const gp_Pnt& thePnt )
5951   {
5952     map<double, const SMDS_MeshNode*> dist2Nodes;
5953     myOctreeNode->NodesAround( thePnt.Coord(), dist2Nodes, myHalfLeafSize );
5954     if ( !dist2Nodes.empty() )
5955       return dist2Nodes.begin()->second;
5956     list<const SMDS_MeshNode*> nodes;
5957     //myOctreeNode->NodesAround( &tgtNode, &nodes, myHalfLeafSize );
5958
5959     double minSqDist = DBL_MAX;
5960     if ( nodes.empty() )  // get all nodes of OctreeNode's closest to thePnt
5961     {
5962       // sort leafs by their distance from thePnt
5963       typedef map< double, SMESH_OctreeNode* > TDistTreeMap;
5964       TDistTreeMap treeMap;
5965       list< SMESH_OctreeNode* > treeList;
5966       list< SMESH_OctreeNode* >::iterator trIt;
5967       treeList.push_back( myOctreeNode );
5968
5969       gp_XYZ pointNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
5970       bool pointInside = myOctreeNode->isInside( pointNode, myHalfLeafSize );
5971       for ( trIt = treeList.begin(); trIt != treeList.end(); ++trIt)
5972       {
5973         SMESH_OctreeNode* tree = *trIt;
5974         if ( !tree->isLeaf() ) // put children to the queue
5975         {
5976           if ( pointInside && !tree->isInside( pointNode, myHalfLeafSize )) continue;
5977           SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
5978           while ( cIt->more() )
5979             treeList.push_back( cIt->next() );
5980         }
5981         else if ( tree->NbNodes() ) // put a tree to the treeMap
5982         {
5983           const Bnd_B3d& box = tree->getBox();
5984           double sqDist = thePnt.SquareDistance( 0.5 * ( box.CornerMin() + box.CornerMax() ));
5985           pair<TDistTreeMap::iterator,bool> it_in = treeMap.insert( make_pair( sqDist, tree ));
5986           if ( !it_in.second ) // not unique distance to box center
5987             treeMap.insert( it_in.first, make_pair( sqDist + 1e-13*treeMap.size(), tree ));
5988         }
5989       }
5990       // find distance after which there is no sense to check tree's
5991       double sqLimit = DBL_MAX;
5992       TDistTreeMap::iterator sqDist_tree = treeMap.begin();
5993       if ( treeMap.size() > 5 ) {
5994         SMESH_OctreeNode* closestTree = sqDist_tree->second;
5995         const Bnd_B3d& box = closestTree->getBox();
5996         double limit = sqrt( sqDist_tree->first ) + sqrt ( box.SquareExtent() );
5997         sqLimit = limit * limit;
5998       }
5999       // get all nodes from trees
6000       for ( ; sqDist_tree != treeMap.end(); ++sqDist_tree) {
6001         if ( sqDist_tree->first > sqLimit )
6002           break;
6003         SMESH_OctreeNode* tree = sqDist_tree->second;
6004         tree->NodesAround( tree->GetNodeIterator()->next(), &nodes );
6005       }
6006     }
6007     // find closest among nodes
6008     minSqDist = DBL_MAX;
6009     const SMDS_MeshNode* closestNode = 0;
6010     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
6011     for ( ; nIt != nodes.end(); ++nIt ) {
6012       double sqDist = thePnt.SquareDistance( SMESH_TNodeXYZ( *nIt ) );
6013       if ( minSqDist > sqDist ) {
6014         closestNode = *nIt;
6015         minSqDist = sqDist;
6016       }
6017     }
6018     return closestNode;
6019   }
6020
6021   //---------------------------------------------------------------------
6022   /*!
6023    * \brief Destructor
6024    */
6025   ~SMESH_NodeSearcherImpl() { delete myOctreeNode; }
6026
6027   //---------------------------------------------------------------------
6028   /*!
6029    * \brief Return the node tree
6030    */
6031   const SMESH_OctreeNode* getTree() const { return myOctreeNode; }
6032
6033 private:
6034   SMESH_OctreeNode* myOctreeNode;
6035   SMESHDS_Mesh*     myMesh;
6036   double            myHalfLeafSize; // max size of a leaf box
6037 };
6038
6039 //=======================================================================
6040 /*!
6041  * \brief Return SMESH_NodeSearcher
6042  */
6043 //=======================================================================
6044
6045 SMESH_NodeSearcher* SMESH_MeshEditor::GetNodeSearcher() 
6046 {
6047   return new SMESH_NodeSearcherImpl( GetMeshDS() );
6048 }
6049
6050 // ========================================================================
6051 namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
6052 {
6053   const int MaxNbElemsInLeaf = 10; // maximal number of elements in a leaf of tree
6054   const int MaxLevel         = 7;  // maximal tree height -> nb terminal boxes: 8^7 = 2097152
6055   const double NodeRadius = 1e-9;  // to enlarge bnd box of element
6056
6057   //=======================================================================
6058   /*!
6059    * \brief Octal tree of bounding boxes of elements
6060    */
6061   //=======================================================================
6062
6063   class ElementBndBoxTree : public SMESH_Octree
6064   {
6065   public:
6066
6067     ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, SMDS_ElemIteratorPtr theElemIt = SMDS_ElemIteratorPtr(), double tolerance = NodeRadius );
6068     void getElementsNearPoint( const gp_Pnt& point, TIDSortedElemSet& foundElems);
6069     void getElementsNearLine ( const gp_Ax1& line, TIDSortedElemSet& foundElems);
6070     ~ElementBndBoxTree();
6071
6072   protected:
6073     ElementBndBoxTree() {}
6074     SMESH_Octree* allocateOctreeChild() const { return new ElementBndBoxTree; }
6075     void buildChildrenData();
6076     Bnd_B3d* buildRootBox();
6077   private:
6078     //!< Bounding box of element
6079     struct ElementBox : public Bnd_B3d
6080     {
6081       const SMDS_MeshElement* _element;
6082       int                     _refCount; // an ElementBox can be included in several tree branches
6083       ElementBox(const SMDS_MeshElement* elem, double tolerance);
6084     };
6085     vector< ElementBox* > _elements;
6086   };
6087
6088   //================================================================================
6089   /*!
6090    * \brief ElementBndBoxTree creation
6091    */
6092   //================================================================================
6093
6094   ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, SMDS_ElemIteratorPtr theElemIt, double tolerance)
6095     :SMESH_Octree( new SMESH_Octree::Limit( MaxLevel, /*minSize=*/0. ))
6096   {
6097     int nbElems = mesh.GetMeshInfo().NbElements( elemType );
6098     _elements.reserve( nbElems );
6099
6100     SMDS_ElemIteratorPtr elemIt = theElemIt ? theElemIt : mesh.elementsIterator( elemType );
6101     while ( elemIt->more() )
6102       _elements.push_back( new ElementBox( elemIt->next(),tolerance  ));
6103
6104     if ( _elements.size() > MaxNbElemsInLeaf )
6105       compute();
6106     else
6107       myIsLeaf = true;
6108   }
6109
6110   //================================================================================
6111   /*!
6112    * \brief Destructor
6113    */
6114   //================================================================================
6115
6116   ElementBndBoxTree::~ElementBndBoxTree()
6117   {
6118     for ( int i = 0; i < _elements.size(); ++i )
6119       if ( --_elements[i]->_refCount <= 0 )
6120         delete _elements[i];
6121   }
6122
6123   //================================================================================
6124   /*!
6125    * \brief Return the maximal box
6126    */
6127   //================================================================================
6128
6129   Bnd_B3d* ElementBndBoxTree::buildRootBox()
6130   {
6131     Bnd_B3d* box = new Bnd_B3d;
6132     for ( int i = 0; i < _elements.size(); ++i )
6133       box->Add( *_elements[i] );
6134     return box;
6135   }
6136
6137   //================================================================================
6138   /*!
6139    * \brief Redistrubute element boxes among children
6140    */
6141   //================================================================================
6142
6143   void ElementBndBoxTree::buildChildrenData()
6144   {
6145     for ( int i = 0; i < _elements.size(); ++i )
6146     {
6147       for (int j = 0; j < 8; j++)
6148       {
6149         if ( !_elements[i]->IsOut( myChildren[j]->getBox() ))
6150         {
6151           _elements[i]->_refCount++;
6152           ((ElementBndBoxTree*)myChildren[j])->_elements.push_back( _elements[i]);
6153         }
6154       }
6155       _elements[i]->_refCount--;
6156     }
6157     _elements.clear();
6158
6159     for (int j = 0; j < 8; j++)
6160     {
6161       ElementBndBoxTree* child = static_cast<ElementBndBoxTree*>( myChildren[j]);
6162       if ( child->_elements.size() <= MaxNbElemsInLeaf )
6163         child->myIsLeaf = true;
6164
6165       if ( child->_elements.capacity() - child->_elements.size() > 1000 )
6166         child->_elements.resize( child->_elements.size() ); // compact
6167     }
6168   }
6169
6170   //================================================================================
6171   /*!
6172    * \brief Return elements which can include the point
6173    */
6174   //================================================================================
6175
6176   void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt&     point,
6177                                                 TIDSortedElemSet& foundElems)
6178   {
6179     if ( level() && getBox().IsOut( point.XYZ() ))
6180       return;
6181
6182     if ( isLeaf() )
6183     {
6184       for ( int i = 0; i < _elements.size(); ++i )
6185         if ( !_elements[i]->IsOut( point.XYZ() ))
6186           foundElems.insert( _elements[i]->_element );
6187     }
6188     else
6189     {
6190       for (int i = 0; i < 8; i++)
6191         ((ElementBndBoxTree*) myChildren[i])->getElementsNearPoint( point, foundElems );
6192     }
6193   }
6194
6195   //================================================================================
6196   /*!
6197    * \brief Return elements which can be intersected by the line
6198    */
6199   //================================================================================
6200
6201   void ElementBndBoxTree::getElementsNearLine( const gp_Ax1&     line,
6202                                                TIDSortedElemSet& foundElems)
6203   {
6204     if ( level() && getBox().IsOut( line ))
6205       return;
6206
6207     if ( isLeaf() )
6208     {
6209       for ( int i = 0; i < _elements.size(); ++i )
6210         if ( !_elements[i]->IsOut( line ))
6211           foundElems.insert( _elements[i]->_element );
6212     }
6213     else
6214     {
6215       for (int i = 0; i < 8; i++)
6216         ((ElementBndBoxTree*) myChildren[i])->getElementsNearLine( line, foundElems );
6217     }
6218   }
6219
6220   //================================================================================
6221   /*!
6222    * \brief Construct the element box
6223    */
6224   //================================================================================
6225
6226   ElementBndBoxTree::ElementBox::ElementBox(const SMDS_MeshElement* elem, double tolerance)
6227   {
6228     _element  = elem;
6229     _refCount = 1;
6230     SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
6231     while ( nIt->more() )
6232       Add( SMESH_TNodeXYZ( cast2Node( nIt->next() )));
6233     Enlarge( tolerance );
6234   }
6235
6236 } // namespace
6237
6238 //=======================================================================
6239 /*!
6240  * \brief Implementation of search for the elements by point and
6241  *        of classification of point in 2D mesh
6242  */
6243 //=======================================================================
6244
6245 struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher
6246 {
6247   SMESHDS_Mesh*                _mesh;
6248   SMDS_ElemIteratorPtr         _meshPartIt;
6249   ElementBndBoxTree*           _ebbTree;
6250   SMESH_NodeSearcherImpl*      _nodeSearcher;
6251   SMDSAbs_ElementType          _elementType;
6252   double                       _tolerance;
6253   bool                         _outerFacesFound;
6254   set<const SMDS_MeshElement*> _outerFaces; // empty means "no internal faces at all"
6255
6256   SMESH_ElementSearcherImpl( SMESHDS_Mesh& mesh, SMDS_ElemIteratorPtr elemIt=SMDS_ElemIteratorPtr())
6257     : _mesh(&mesh),_meshPartIt(elemIt),_ebbTree(0),_nodeSearcher(0),_tolerance(-1),_outerFacesFound(false) {}
6258   ~SMESH_ElementSearcherImpl()
6259   {
6260     if ( _ebbTree )      delete _ebbTree;      _ebbTree      = 0;
6261     if ( _nodeSearcher ) delete _nodeSearcher; _nodeSearcher = 0;
6262   }
6263   virtual int FindElementsByPoint(const gp_Pnt&                      point,
6264                                   SMDSAbs_ElementType                type,
6265                                   vector< const SMDS_MeshElement* >& foundElements);
6266   virtual TopAbs_State GetPointState(const gp_Pnt& point);
6267
6268   void GetElementsNearLine( const gp_Ax1&                      line,
6269                             SMDSAbs_ElementType                type,
6270                             vector< const SMDS_MeshElement* >& foundElems);
6271   double getTolerance();
6272   bool getIntersParamOnLine(const gp_Lin& line, const SMDS_MeshElement* face,
6273                             const double tolerance, double & param);
6274   void findOuterBoundary(const SMDS_MeshElement* anyOuterFace);
6275   bool isOuterBoundary(const SMDS_MeshElement* face) const
6276   {
6277     return _outerFaces.empty() || _outerFaces.count(face);
6278   }
6279   struct TInters //!< data of intersection of the line and the mesh face (used in GetPointState())
6280   {
6281     const SMDS_MeshElement* _face;
6282     gp_Vec                  _faceNorm;
6283     bool                    _coincides; //!< the line lays in face plane
6284     TInters(const SMDS_MeshElement* face, const gp_Vec& faceNorm, bool coinc=false)
6285       : _face(face), _faceNorm( faceNorm ), _coincides( coinc ) {}
6286   };
6287   struct TFaceLink //!< link and faces sharing it (used in findOuterBoundary())
6288   {
6289     SMESH_TLink      _link;
6290     TIDSortedElemSet _faces;
6291     TFaceLink( const SMDS_MeshNode* n1, const SMDS_MeshNode* n2, const SMDS_MeshElement* face)
6292       : _link( n1, n2 ), _faces( &face, &face + 1) {}
6293   };
6294 };
6295
6296 ostream& operator<< (ostream& out, const SMESH_ElementSearcherImpl::TInters& i)
6297 {
6298   return out << "TInters(face=" << ( i._face ? i._face->GetID() : 0)
6299              << ", _coincides="<<i._coincides << ")";
6300 }
6301
6302 //=======================================================================
6303 /*!
6304  * \brief define tolerance for search
6305  */
6306 //=======================================================================
6307
6308 double SMESH_ElementSearcherImpl::getTolerance()
6309 {
6310   if ( _tolerance < 0 )
6311   {
6312     const SMDS_MeshInfo& meshInfo = _mesh->GetMeshInfo();
6313
6314     _tolerance = 0;
6315     if ( _nodeSearcher && meshInfo.NbNodes() > 1 )
6316     {
6317       double boxSize = _nodeSearcher->getTree()->maxSize();
6318       _tolerance = 1e-8 * boxSize/* / meshInfo.NbNodes()*/;
6319     }
6320     else if ( _ebbTree && meshInfo.NbElements() > 0 )
6321     {
6322       double boxSize = _ebbTree->maxSize();
6323       _tolerance = 1e-8 * boxSize/* / meshInfo.NbElements()*/;
6324     }
6325     if ( _tolerance == 0 )
6326     {
6327       // define tolerance by size of a most complex element
6328       int complexType = SMDSAbs_Volume;
6329       while ( complexType > SMDSAbs_All &&
6330               meshInfo.NbElements( SMDSAbs_ElementType( complexType )) < 1 )
6331         --complexType;
6332       if ( complexType == SMDSAbs_All ) return 0; // empty mesh
6333       double elemSize;
6334       if ( complexType == int( SMDSAbs_Node ))
6335       {
6336         SMDS_NodeIteratorPtr nodeIt = _mesh->nodesIterator();
6337         elemSize = 1;
6338         if ( meshInfo.NbNodes() > 2 )
6339           elemSize = SMESH_TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() );
6340       }
6341       else
6342       {
6343         SMDS_ElemIteratorPtr elemIt =
6344             _mesh->elementsIterator( SMDSAbs_ElementType( complexType ));
6345         const SMDS_MeshElement* elem = elemIt->next();
6346         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
6347         SMESH_TNodeXYZ n1( cast2Node( nodeIt->next() ));
6348         elemSize = 0;
6349         while ( nodeIt->more() )
6350         {
6351           double dist = n1.Distance( cast2Node( nodeIt->next() ));
6352           elemSize = max( dist, elemSize );
6353         }
6354       }
6355       _tolerance = 1e-4 * elemSize;
6356     }
6357   }
6358   return _tolerance;
6359 }
6360
6361 //================================================================================
6362 /*!
6363  * \brief Find intersection of the line and an edge of face and return parameter on line
6364  */
6365 //================================================================================
6366
6367 bool SMESH_ElementSearcherImpl::getIntersParamOnLine(const gp_Lin&           line,
6368                                                      const SMDS_MeshElement* face,
6369                                                      const double            tol,
6370                                                      double &                param)
6371 {
6372   int nbInts = 0;
6373   param = 0;
6374
6375   GeomAPI_ExtremaCurveCurve anExtCC;
6376   Handle(Geom_Curve) lineCurve = new Geom_Line( line );
6377   
6378   int nbNodes = face->IsQuadratic() ? face->NbNodes()/2 : face->NbNodes();
6379   for ( int i = 0; i < nbNodes && nbInts < 2; ++i )
6380   {
6381     GC_MakeSegment edge( SMESH_TNodeXYZ( face->GetNode( i )),
6382                          SMESH_TNodeXYZ( face->GetNode( (i+1)%nbNodes) )); 
6383     anExtCC.Init( lineCurve, edge);
6384     if ( anExtCC.NbExtrema() > 0 && anExtCC.LowerDistance() <= tol)
6385     {
6386       Quantity_Parameter pl, pe;
6387       anExtCC.LowerDistanceParameters( pl, pe );
6388       param += pl;
6389       if ( ++nbInts == 2 )
6390         break;
6391     }
6392   }
6393   if ( nbInts > 0 ) param /= nbInts;
6394   return nbInts > 0;
6395 }
6396 //================================================================================
6397 /*!
6398  * \brief Find all faces belonging to the outer boundary of mesh
6399  */
6400 //================================================================================
6401
6402 void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerFace)
6403 {
6404   if ( _outerFacesFound ) return;
6405
6406   // Collect all outer faces by passing from one outer face to another via their links
6407   // and BTW find out if there are internal faces at all.
6408
6409   // checked links and links where outer boundary meets internal one
6410   set< SMESH_TLink > visitedLinks, seamLinks;
6411
6412   // links to treat with already visited faces sharing them
6413   list < TFaceLink > startLinks;
6414
6415   // load startLinks with the first outerFace
6416   startLinks.push_back( TFaceLink( outerFace->GetNode(0), outerFace->GetNode(1), outerFace));
6417   _outerFaces.insert( outerFace );
6418
6419   TIDSortedElemSet emptySet;
6420   while ( !startLinks.empty() )
6421   {
6422     const SMESH_TLink& link  = startLinks.front()._link;
6423     TIDSortedElemSet&  faces = startLinks.front()._faces;
6424
6425     outerFace = *faces.begin();
6426     // find other faces sharing the link
6427     const SMDS_MeshElement* f;
6428     while (( f = SMESH_MeshEditor::FindFaceInSet(link.node1(), link.node2(), emptySet, faces )))
6429       faces.insert( f );
6430
6431     // select another outer face among the found 
6432     const SMDS_MeshElement* outerFace2 = 0;
6433     if ( faces.size() == 2 )
6434     {
6435       outerFace2 = (outerFace == *faces.begin() ? *faces.rbegin() : *faces.begin());
6436     }
6437     else if ( faces.size() > 2 )
6438     {
6439       seamLinks.insert( link );
6440
6441       // link direction within the outerFace
6442       gp_Vec n1n2( SMESH_TNodeXYZ( link.node1()),
6443                    SMESH_TNodeXYZ( link.node2()));
6444       int i1 = outerFace->GetNodeIndex( link.node1() );
6445       int i2 = outerFace->GetNodeIndex( link.node2() );
6446       bool rev = ( abs(i2-i1) == 1 ? i1 > i2 : i2 > i1 );
6447       if ( rev ) n1n2.Reverse();
6448       // outerFace normal
6449       gp_XYZ ofNorm, fNorm;
6450       if ( SMESH_Algo::FaceNormal( outerFace, ofNorm, /*normalized=*/false ))
6451       {
6452         // direction from the link inside outerFace
6453         gp_Vec dirInOF = gp_Vec( ofNorm ) ^ n1n2;
6454         // sort all other faces by angle with the dirInOF
6455         map< double, const SMDS_MeshElement* > angle2Face;
6456         set< const SMDS_MeshElement*, TIDCompare >::const_iterator face = faces.begin();
6457         for ( ; face != faces.end(); ++face )
6458         {
6459           if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false ))
6460             continue;
6461           gp_Vec dirInF = gp_Vec( fNorm ) ^ n1n2;
6462           double angle = dirInOF.AngleWithRef( dirInF, n1n2 );
6463           if ( angle < 0 ) angle += 2. * M_PI;
6464           angle2Face.insert( make_pair( angle, *face ));
6465         }
6466         if ( !angle2Face.empty() )
6467           outerFace2 = angle2Face.begin()->second;
6468       }
6469     }
6470     // store the found outer face and add its links to continue seaching from
6471     if ( outerFace2 )
6472     {
6473       _outerFaces.insert( outerFace );
6474       int nbNodes = outerFace2->NbNodes()/( outerFace2->IsQuadratic() ? 2 : 1 );
6475       for ( int i = 0; i < nbNodes; ++i )
6476       {
6477         SMESH_TLink link2( outerFace2->GetNode(i), outerFace2->GetNode((i+1)%nbNodes));
6478         if ( visitedLinks.insert( link2 ).second )
6479           startLinks.push_back( TFaceLink( link2.node1(), link2.node2(), outerFace2 ));
6480       }
6481     }
6482     startLinks.pop_front();
6483   }
6484   _outerFacesFound = true;
6485
6486   if ( !seamLinks.empty() )
6487   {
6488     // There are internal boundaries touching the outher one,
6489     // find all faces of internal boundaries in order to find
6490     // faces of boundaries of holes, if any.
6491     
6492   }
6493   else
6494   {
6495     _outerFaces.clear();
6496   }
6497 }
6498
6499 //=======================================================================
6500 /*!
6501  * \brief Find elements of given type where the given point is IN or ON.
6502  *        Returns nb of found elements and elements them-selves.
6503  *
6504  * 'ALL' type means elements of any type excluding nodes and 0D elements
6505  */
6506 //=======================================================================
6507
6508 int SMESH_ElementSearcherImpl::
6509 FindElementsByPoint(const gp_Pnt&                      point,
6510                     SMDSAbs_ElementType                type,
6511                     vector< const SMDS_MeshElement* >& foundElements)
6512 {
6513   foundElements.clear();
6514
6515   double tolerance = getTolerance();
6516
6517   // =================================================================================
6518   if ( type == SMDSAbs_Node || type == SMDSAbs_0DElement )
6519   {
6520     if ( !_nodeSearcher )
6521       _nodeSearcher = new SMESH_NodeSearcherImpl( _mesh );
6522
6523     const SMDS_MeshNode* closeNode = _nodeSearcher->FindClosestTo( point );
6524     if ( !closeNode ) return foundElements.size();
6525
6526     if ( point.Distance( SMESH_TNodeXYZ( closeNode )) > tolerance )
6527       return foundElements.size(); // to far from any node
6528
6529     if ( type == SMDSAbs_Node )
6530     {
6531       foundElements.push_back( closeNode );
6532     }
6533     else
6534     {
6535       SMDS_ElemIteratorPtr elemIt = closeNode->GetInverseElementIterator( SMDSAbs_0DElement );
6536       while ( elemIt->more() )
6537         foundElements.push_back( elemIt->next() );
6538     }
6539   }
6540   // =================================================================================
6541   else // elements more complex than 0D
6542   {
6543     if ( !_ebbTree || _elementType != type )
6544     {
6545       if ( _ebbTree ) delete _ebbTree;
6546       _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt, tolerance );
6547     }
6548     TIDSortedElemSet suspectElems;
6549     _ebbTree->getElementsNearPoint( point, suspectElems );
6550     TIDSortedElemSet::iterator elem = suspectElems.begin();
6551     for ( ; elem != suspectElems.end(); ++elem )
6552       if ( !SMESH_MeshEditor::isOut( *elem, point, tolerance ))
6553         foundElements.push_back( *elem );
6554   }
6555   return foundElements.size();
6556 }
6557
6558 //================================================================================
6559 /*!
6560  * \brief Classify the given point in the closed 2D mesh
6561  */
6562 //================================================================================
6563
6564 TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
6565 {
6566   double tolerance = getTolerance();
6567   if ( !_ebbTree || _elementType != SMDSAbs_Face )
6568   {
6569     if ( _ebbTree ) delete _ebbTree;
6570     _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = SMDSAbs_Face, _meshPartIt );
6571   }
6572   // Algo: analyse transition of a line starting at the point through mesh boundary;
6573   // try three lines parallel to axis of the coordinate system and perform rough
6574   // analysis. If solution is not clear perform thorough analysis.
6575
6576   const int nbAxes = 3;
6577   gp_Dir axisDir[ nbAxes ] = { gp::DX(), gp::DY(), gp::DZ() };
6578   map< double, TInters >   paramOnLine2TInters[ nbAxes ];
6579   list< TInters > tangentInters[ nbAxes ]; // of faces whose plane includes the line
6580   multimap< int, int > nbInt2Axis; // to find the simplest case
6581   for ( int axis = 0; axis < nbAxes; ++axis )
6582   {
6583     gp_Ax1 lineAxis( point, axisDir[axis]);
6584     gp_Lin line    ( lineAxis );
6585
6586     TIDSortedElemSet suspectFaces; // faces possibly intersecting the line
6587     _ebbTree->getElementsNearLine( lineAxis, suspectFaces );
6588
6589     // Intersect faces with the line
6590
6591     map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6592     TIDSortedElemSet::iterator face = suspectFaces.begin();
6593     for ( ; face != suspectFaces.end(); ++face )
6594     {
6595       // get face plane
6596       gp_XYZ fNorm;
6597       if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false)) continue;
6598       gp_Pln facePlane( SMESH_TNodeXYZ( (*face)->GetNode(0)), fNorm );
6599
6600       // perform intersection
6601       IntAna_IntConicQuad intersection( line, IntAna_Quadric( facePlane ));
6602       if ( !intersection.IsDone() )
6603         continue;
6604       if ( intersection.IsInQuadric() )
6605       {
6606         tangentInters[ axis ].push_back( TInters( *face, fNorm, true ));
6607       }
6608       else if ( ! intersection.IsParallel() && intersection.NbPoints() > 0 )
6609       {
6610         gp_Pnt intersectionPoint = intersection.Point(1);
6611         if ( !SMESH_MeshEditor::isOut( *face, intersectionPoint, tolerance ))
6612           u2inters.insert(make_pair( intersection.ParamOnConic(1), TInters( *face, fNorm )));
6613       }
6614     }
6615     // Analyse intersections roughly
6616
6617     int nbInter = u2inters.size();
6618     if ( nbInter == 0 )
6619       return TopAbs_OUT; 
6620
6621     double f = u2inters.begin()->first, l = u2inters.rbegin()->first;
6622     if ( nbInter == 1 ) // not closed mesh
6623       return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6624
6625     if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6626       return TopAbs_ON;
6627
6628     if ( (f<0) == (l<0) )
6629       return TopAbs_OUT;
6630
6631     int nbIntBeforePoint = std::distance( u2inters.begin(), u2inters.lower_bound(0));
6632     int nbIntAfterPoint  = nbInter - nbIntBeforePoint;
6633     if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6634       return TopAbs_IN;
6635
6636     nbInt2Axis.insert( make_pair( min( nbIntBeforePoint, nbIntAfterPoint ), axis ));
6637
6638     if ( _outerFacesFound ) break; // pass to thorough analysis
6639
6640   } // three attempts - loop on CS axes
6641
6642   // Analyse intersections thoroughly.
6643   // We make two loops maximum, on the first one we only exclude touching intersections,
6644   // on the second, if situation is still unclear, we gather and use information on
6645   // position of faces (internal or outer). If faces position is already gathered,
6646   // we make the second loop right away.
6647
6648   for ( int hasPositionInfo = _outerFacesFound; hasPositionInfo < 2; ++hasPositionInfo )
6649   {
6650     multimap< int, int >::const_iterator nb_axis = nbInt2Axis.begin();
6651     for ( ; nb_axis != nbInt2Axis.end(); ++nb_axis )
6652     {
6653       int axis = nb_axis->second;
6654       map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6655
6656       gp_Ax1 lineAxis( point, axisDir[axis]);
6657       gp_Lin line    ( lineAxis );
6658
6659       // add tangent intersections to u2inters
6660       double param;
6661       list< TInters >::const_iterator tgtInt = tangentInters[ axis ].begin();
6662       for ( ; tgtInt != tangentInters[ axis ].end(); ++tgtInt )
6663         if ( getIntersParamOnLine( line, tgtInt->_face, tolerance, param ))
6664           u2inters.insert(make_pair( param, *tgtInt ));
6665       tangentInters[ axis ].clear();
6666
6667       // Count intersections before and after the point excluding touching ones.
6668       // If hasPositionInfo we count intersections of outer boundary only
6669
6670       int nbIntBeforePoint = 0, nbIntAfterPoint = 0;
6671       double f = numeric_limits<double>::max(), l = -numeric_limits<double>::max();
6672       map< double, TInters >::iterator u_int1 = u2inters.begin(), u_int2 = u_int1;
6673       bool ok = ! u_int1->second._coincides;
6674       while ( ok && u_int1 != u2inters.end() )
6675       {
6676         double u = u_int1->first;
6677         bool touchingInt = false;
6678         if ( ++u_int2 != u2inters.end() )
6679         {
6680           // skip intersections at the same point (if the line passes through edge or node)
6681           int nbSamePnt = 0;
6682           while ( u_int2 != u2inters.end() && fabs( u_int2->first - u ) < tolerance )
6683           {
6684             ++nbSamePnt;
6685             ++u_int2;
6686           }
6687
6688           // skip tangent intersections
6689           int nbTgt = 0;
6690           const SMDS_MeshElement* prevFace = u_int1->second._face;
6691           while ( ok && u_int2->second._coincides )
6692           {
6693             if ( SMESH_Algo::GetCommonNodes(prevFace , u_int2->second._face).empty() )
6694               ok = false;
6695             else
6696             {
6697               nbTgt++;
6698               u_int2++;
6699               ok = ( u_int2 != u2inters.end() );
6700             }
6701           }
6702           if ( !ok ) break;
6703
6704           // skip intersections at the same point after tangent intersections
6705           if ( nbTgt > 0 )
6706           {
6707             double u2 = u_int2->first;
6708             ++u_int2;
6709             while ( u_int2 != u2inters.end() && fabs( u_int2->first - u2 ) < tolerance )
6710             {
6711               ++nbSamePnt;
6712               ++u_int2;
6713             }
6714           }
6715           // decide if we skipped a touching intersection
6716           if ( nbSamePnt + nbTgt > 0 )
6717           {
6718             double minDot = numeric_limits<double>::max(), maxDot = -numeric_limits<double>::max();
6719             map< double, TInters >::iterator u_int = u_int1;
6720             for ( ; u_int != u_int2; ++u_int )
6721             {
6722               if ( u_int->second._coincides ) continue;
6723               double dot = u_int->second._faceNorm * line.Direction();
6724               if ( dot > maxDot ) maxDot = dot;
6725               if ( dot < minDot ) minDot = dot;
6726             }
6727             touchingInt = ( minDot*maxDot < 0 );
6728           }
6729         }
6730         if ( !touchingInt )
6731         {
6732           if ( !hasPositionInfo || isOuterBoundary( u_int1->second._face ))
6733           {
6734             if ( u < 0 )
6735               ++nbIntBeforePoint;
6736             else
6737               ++nbIntAfterPoint;
6738           }
6739           if ( u < f ) f = u;
6740           if ( u > l ) l = u;
6741         }
6742
6743         u_int1 = u_int2; // to next intersection
6744
6745       } // loop on intersections with one line
6746
6747       if ( ok )
6748       {
6749         if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6750           return TopAbs_ON;
6751
6752         if ( nbIntBeforePoint == 0  || nbIntAfterPoint == 0)
6753           return TopAbs_OUT; 
6754
6755         if ( nbIntBeforePoint + nbIntAfterPoint == 1 ) // not closed mesh
6756           return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6757
6758         if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6759           return TopAbs_IN;
6760
6761         if ( (f<0) == (l<0) )
6762           return TopAbs_OUT;
6763
6764         if ( hasPositionInfo )
6765           return nbIntBeforePoint % 2 ? TopAbs_IN : TopAbs_OUT;
6766       }
6767     } // loop on intersections of the tree lines - thorough analysis
6768
6769     if ( !hasPositionInfo )
6770     {
6771       // gather info on faces position - is face in the outer boundary or not
6772       map< double, TInters > & u2inters = paramOnLine2TInters[ 0 ];
6773       findOuterBoundary( u2inters.begin()->second._face );
6774     }
6775
6776   } // two attempts - with and w/o faces position info in the mesh
6777
6778   return TopAbs_UNKNOWN;
6779 }
6780
6781 //=======================================================================
6782 /*!
6783  * \brief Return elements possibly intersecting the line
6784  */
6785 //=======================================================================
6786
6787 void SMESH_ElementSearcherImpl::GetElementsNearLine( const gp_Ax1&                      line,
6788                                                      SMDSAbs_ElementType                type,
6789                                                      vector< const SMDS_MeshElement* >& foundElems)
6790 {
6791   if ( !_ebbTree || _elementType != type )
6792   {
6793     if ( _ebbTree ) delete _ebbTree;
6794     _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt );
6795   }
6796   TIDSortedElemSet suspectFaces; // elements possibly intersecting the line
6797   _ebbTree->getElementsNearLine( line, suspectFaces );
6798   foundElems.assign( suspectFaces.begin(), suspectFaces.end());
6799 }
6800
6801 //=======================================================================
6802 /*!
6803  * \brief Return SMESH_ElementSearcher
6804  */
6805 //=======================================================================
6806
6807 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher()
6808 {
6809   return new SMESH_ElementSearcherImpl( *GetMeshDS() );
6810 }
6811
6812 //=======================================================================
6813 /*!
6814  * \brief Return SMESH_ElementSearcher acting on a sub-set of elements
6815  */
6816 //=======================================================================
6817
6818 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher(SMDS_ElemIteratorPtr elemIt)
6819 {
6820   return new SMESH_ElementSearcherImpl( *GetMeshDS(), elemIt );
6821 }
6822
6823 //=======================================================================
6824 /*!
6825  * \brief Return true if the point is IN or ON of the element
6826  */
6827 //=======================================================================
6828
6829 bool SMESH_MeshEditor::isOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol )
6830 {
6831   if ( element->GetType() == SMDSAbs_Volume)
6832   {
6833     return SMDS_VolumeTool( element ).IsOut( point.X(), point.Y(), point.Z(), tol );
6834   }
6835
6836   // get ordered nodes
6837
6838   vector< gp_XYZ > xyz;
6839   vector<const SMDS_MeshNode*> nodeList;
6840
6841   SMDS_ElemIteratorPtr nodeIt = element->nodesIterator();
6842   if ( element->IsQuadratic() ) {
6843     if (const SMDS_VtkFace* f=dynamic_cast<const SMDS_VtkFace*>(element))
6844       nodeIt = f->interlacedNodesElemIterator();
6845     else if (const SMDS_VtkEdge*  e =dynamic_cast<const SMDS_VtkEdge*>(element))
6846       nodeIt = e->interlacedNodesElemIterator();
6847   }
6848   while ( nodeIt->more() )
6849     {
6850       const SMDS_MeshNode* node = cast2Node( nodeIt->next() );
6851       xyz.push_back( SMESH_TNodeXYZ(node) );
6852       nodeList.push_back(node);
6853     }
6854
6855   int i, nbNodes = element->NbNodes();
6856
6857   if ( element->GetType() == SMDSAbs_Face ) // --------------------------------------------------
6858   {
6859     // compute face normal
6860     gp_Vec faceNorm(0,0,0);
6861     xyz.push_back( xyz.front() );
6862     nodeList.push_back( nodeList.front() );
6863     for ( i = 0; i < nbNodes; ++i )
6864     {
6865       gp_Vec edge1( xyz[i+1], xyz[i]);
6866       gp_Vec edge2( xyz[i+1], xyz[(i+2)%nbNodes] );
6867       faceNorm += edge1 ^ edge2;
6868     }
6869     double normSize = faceNorm.Magnitude();
6870     if ( normSize <= tol )
6871     {
6872       // degenerated face: point is out if it is out of all face edges
6873       for ( i = 0; i < nbNodes; ++i )
6874       {
6875         SMDS_LinearEdge edge( nodeList[i], nodeList[i+1] );
6876         if ( !isOut( &edge, point, tol ))
6877           return false;
6878       }
6879       return true;
6880     }
6881     faceNorm /= normSize;
6882
6883     // check if the point lays on face plane
6884     gp_Vec n2p( xyz[0], point );
6885     if ( fabs( n2p * faceNorm ) > tol )
6886       return true; // not on face plane
6887
6888     // check if point is out of face boundary:
6889     // define it by closest transition of a ray point->infinity through face boundary
6890     // on the face plane.
6891     // First, find normal of a plane perpendicular to face plane, to be used as a cutting tool
6892     // to find intersections of the ray with the boundary.
6893     gp_Vec ray = n2p;
6894     gp_Vec plnNorm = ray ^ faceNorm;
6895     normSize = plnNorm.Magnitude();
6896     if ( normSize <= tol ) return false; // point coincides with the first node
6897     plnNorm /= normSize;
6898     // for each node of the face, compute its signed distance to the plane
6899     vector<double> dist( nbNodes + 1);
6900     for ( i = 0; i < nbNodes; ++i )
6901     {
6902       gp_Vec n2p( xyz[i], point );
6903       dist[i] = n2p * plnNorm;
6904     }
6905     dist.back() = dist.front();
6906     // find the closest intersection
6907     int    iClosest = -1;
6908     double rClosest, distClosest = 1e100;;
6909     gp_Pnt pClosest;
6910     for ( i = 0; i < nbNodes; ++i )
6911     {
6912       double r;
6913       if ( fabs( dist[i]) < tol )
6914         r = 0.;
6915       else if ( fabs( dist[i+1]) < tol )
6916         r = 1.;
6917       else if ( dist[i] * dist[i+1] < 0 )
6918         r = dist[i] / ( dist[i] - dist[i+1] );
6919       else
6920         continue; // no intersection
6921       gp_Pnt pInt = xyz[i] * (1.-r) + xyz[i+1] * r;
6922       gp_Vec p2int ( point, pInt);
6923       if ( p2int * ray > -tol ) // right half-space
6924       {
6925         double intDist = p2int.SquareMagnitude();
6926         if ( intDist < distClosest )
6927         {
6928           iClosest = i;
6929           rClosest = r;
6930           pClosest = pInt;
6931           distClosest = intDist;
6932         }
6933       }
6934     }
6935     if ( iClosest < 0 )
6936       return true; // no intesections - out
6937
6938     // analyse transition
6939     gp_Vec edge( xyz[iClosest], xyz[iClosest+1] );
6940     gp_Vec edgeNorm = -( edge ^ faceNorm ); // normal to intersected edge pointing out of face
6941     gp_Vec p2int ( point, pClosest );
6942     bool out = (edgeNorm * p2int) < -tol;
6943     if ( rClosest > 0. && rClosest < 1. ) // not node intersection
6944       return out;
6945
6946     // ray pass through a face node; analyze transition through an adjacent edge
6947     gp_Pnt p1 = xyz[ (rClosest == 0.) ? ((iClosest+nbNodes-1) % nbNodes) : (iClosest+1) ];
6948     gp_Pnt p2 = xyz[ (rClosest == 0.) ? iClosest : ((iClosest+2) % nbNodes) ];
6949     gp_Vec edgeAdjacent( p1, p2 );
6950     gp_Vec edgeNorm2 = -( edgeAdjacent ^ faceNorm );
6951     bool out2 = (edgeNorm2 * p2int) < -tol;
6952
6953     bool covexCorner = ( edgeNorm * edgeAdjacent * (rClosest==1. ? 1. : -1.)) < 0;
6954     return covexCorner ? (out || out2) : (out && out2);
6955   }
6956   if ( element->GetType() == SMDSAbs_Edge ) // --------------------------------------------------
6957   {
6958     // point is out of edge if it is NOT ON any straight part of edge
6959     // (we consider quadratic edge as being composed of two straight parts)
6960     for ( i = 1; i < nbNodes; ++i )
6961     {
6962       gp_Vec edge( xyz[i-1], xyz[i]);
6963       gp_Vec n1p ( xyz[i-1], point);
6964       double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude();
6965       if ( dist > tol )
6966         continue;
6967       gp_Vec n2p( xyz[i], point );
6968       if ( fabs( edge.Magnitude() - n1p.Magnitude() - n2p.Magnitude()) > tol )
6969         continue;
6970       return false; // point is ON this part
6971     }
6972     return true;
6973   }
6974   // Node or 0D element -------------------------------------------------------------------------
6975   {
6976     gp_Vec n2p ( xyz[0], point );
6977     return n2p.Magnitude() <= tol;
6978   }
6979   return true;
6980 }
6981
6982 //=======================================================================
6983 //function : SimplifyFace
6984 //purpose  :
6985 //=======================================================================
6986 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *> faceNodes,
6987                                     vector<const SMDS_MeshNode *>&      poly_nodes,
6988                                     vector<int>&                        quantities) const
6989 {
6990   int nbNodes = faceNodes.size();
6991
6992   if (nbNodes < 3)
6993     return 0;
6994
6995   set<const SMDS_MeshNode*> nodeSet;
6996
6997   // get simple seq of nodes
6998   //const SMDS_MeshNode* simpleNodes[ nbNodes ];
6999   vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
7000   int iSimple = 0, nbUnique = 0;
7001
7002   simpleNodes[iSimple++] = faceNodes[0];
7003   nbUnique++;
7004   for (int iCur = 1; iCur < nbNodes; iCur++) {
7005     if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
7006       simpleNodes[iSimple++] = faceNodes[iCur];
7007       if (nodeSet.insert( faceNodes[iCur] ).second)
7008         nbUnique++;
7009     }
7010   }
7011   int nbSimple = iSimple;
7012   if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
7013     nbSimple--;
7014     iSimple--;
7015   }
7016
7017   if (nbUnique < 3)
7018     return 0;
7019
7020   // separate loops
7021   int nbNew = 0;
7022   bool foundLoop = (nbSimple > nbUnique);
7023   while (foundLoop) {
7024     foundLoop = false;
7025     set<const SMDS_MeshNode*> loopSet;
7026     for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
7027       const SMDS_MeshNode* n = simpleNodes[iSimple];
7028       if (!loopSet.insert( n ).second) {
7029         foundLoop = true;
7030
7031         // separate loop
7032         int iC = 0, curLast = iSimple;
7033         for (; iC < curLast; iC++) {
7034           if (simpleNodes[iC] == n) break;
7035         }
7036         int loopLen = curLast - iC;
7037         if (loopLen > 2) {
7038           // create sub-element
7039           nbNew++;
7040           quantities.push_back(loopLen);
7041           for (; iC < curLast; iC++) {
7042             poly_nodes.push_back(simpleNodes[iC]);
7043           }
7044         }
7045         // shift the rest nodes (place from the first loop position)
7046         for (iC = curLast + 1; iC < nbSimple; iC++) {
7047           simpleNodes[iC - loopLen] = simpleNodes[iC];
7048         }
7049         nbSimple -= loopLen;
7050         iSimple -= loopLen;
7051       }
7052     } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
7053   } // while (foundLoop)
7054
7055   if (iSimple > 2) {
7056     nbNew++;
7057     quantities.push_back(iSimple);
7058     for (int i = 0; i < iSimple; i++)
7059       poly_nodes.push_back(simpleNodes[i]);
7060   }
7061
7062   return nbNew;
7063 }
7064
7065 //=======================================================================
7066 //function : MergeNodes
7067 //purpose  : In each group, the cdr of nodes are substituted by the first one
7068 //           in all elements.
7069 //=======================================================================
7070
7071 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
7072 {
7073   MESSAGE("MergeNodes");
7074   myLastCreatedElems.Clear();
7075   myLastCreatedNodes.Clear();
7076
7077   SMESHDS_Mesh* aMesh = GetMeshDS();
7078
7079   TNodeNodeMap nodeNodeMap; // node to replace - new node
7080   set<const SMDS_MeshElement*> elems; // all elements with changed nodes
7081   list< int > rmElemIds, rmNodeIds;
7082
7083   // Fill nodeNodeMap and elems
7084
7085   TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
7086   for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
7087     list<const SMDS_MeshNode*>& nodes = *grIt;
7088     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
7089     const SMDS_MeshNode* nToKeep = *nIt;
7090     //MESSAGE("node to keep " << nToKeep->GetID());
7091     for ( ++nIt; nIt != nodes.end(); nIt++ ) {
7092       const SMDS_MeshNode* nToRemove = *nIt;
7093       nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
7094       if ( nToRemove != nToKeep ) {
7095         //MESSAGE("  node to remove " << nToRemove->GetID());
7096         rmNodeIds.push_back( nToRemove->GetID() );
7097         AddToSameGroups( nToKeep, nToRemove, aMesh );
7098       }
7099
7100       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
7101       while ( invElemIt->more() ) {
7102         const SMDS_MeshElement* elem = invElemIt->next();
7103         elems.insert(elem);
7104       }
7105     }
7106   }
7107   // Change element nodes or remove an element
7108
7109   set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
7110   for ( ; eIt != elems.end(); eIt++ ) {
7111     const SMDS_MeshElement* elem = *eIt;
7112     //MESSAGE(" ---- inverse elem on node to remove " << elem->GetID());
7113     int nbNodes = elem->NbNodes();
7114     int aShapeId = FindShape( elem );
7115
7116     set<const SMDS_MeshNode*> nodeSet;
7117     vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
7118     int iUnique = 0, iCur = 0, nbRepl = 0;
7119     vector<int> iRepl( nbNodes );
7120
7121     // get new seq of nodes
7122     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
7123     while ( itN->more() ) {
7124       const SMDS_MeshNode* n =
7125         static_cast<const SMDS_MeshNode*>( itN->next() );
7126
7127       TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
7128       if ( nnIt != nodeNodeMap.end() ) { // n sticks
7129         n = (*nnIt).second;
7130         // BUG 0020185: begin
7131         {
7132           bool stopRecur = false;
7133           set<const SMDS_MeshNode*> nodesRecur;
7134           nodesRecur.insert(n);
7135           while (!stopRecur) {
7136             TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
7137             if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
7138               n = (*nnIt_i).second;
7139               if (!nodesRecur.insert(n).second) {
7140                 // error: recursive dependancy
7141                 stopRecur = true;
7142               }
7143             }
7144             else
7145               stopRecur = true;
7146           }
7147         }
7148         // BUG 0020185: end
7149       }
7150       curNodes[ iCur ] = n;
7151       bool isUnique = nodeSet.insert( n ).second;
7152       if ( isUnique )
7153         uniqueNodes[ iUnique++ ] = n;
7154       else
7155         iRepl[ nbRepl++ ] = iCur;
7156       iCur++;
7157     }
7158
7159     // Analyse element topology after replacement
7160
7161     bool isOk = true;
7162     int nbUniqueNodes = nodeSet.size();
7163     //MESSAGE("nbNodes nbUniqueNodes " << nbNodes << " " << nbUniqueNodes);
7164     if ( nbNodes != nbUniqueNodes ) { // some nodes stick
7165       // Polygons and Polyhedral volumes
7166       if (elem->IsPoly()) {
7167
7168         if (elem->GetType() == SMDSAbs_Face) {
7169           // Polygon
7170           vector<const SMDS_MeshNode *> face_nodes (nbNodes);
7171           int inode = 0;
7172           for (; inode < nbNodes; inode++) {
7173             face_nodes[inode] = curNodes[inode];
7174           }
7175
7176           vector<const SMDS_MeshNode *> polygons_nodes;
7177           vector<int> quantities;
7178           int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
7179           if (nbNew > 0) {
7180             inode = 0;
7181             for (int iface = 0; iface < nbNew; iface++) {
7182               int nbNodes = quantities[iface];
7183               vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
7184               for (int ii = 0; ii < nbNodes; ii++, inode++) {
7185                 poly_nodes[ii] = polygons_nodes[inode];
7186               }
7187               SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
7188               myLastCreatedElems.Append(newElem);
7189               if (aShapeId)
7190                 aMesh->SetMeshElementOnShape(newElem, aShapeId);
7191             }
7192
7193             MESSAGE("ChangeElementNodes MergeNodes Polygon");
7194             //aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
7195             vector<const SMDS_MeshNode *> polynodes(polygons_nodes.begin()+inode,polygons_nodes.end());
7196             int quid =0;
7197             if (nbNew > 0) quid = nbNew - 1;
7198             vector<int> newquant(quantities.begin()+quid, quantities.end());
7199             const SMDS_MeshElement* newElem = 0;
7200             newElem = aMesh->AddPolyhedralVolume(polynodes, newquant);
7201             myLastCreatedElems.Append(newElem);
7202             if ( aShapeId && newElem )
7203               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7204             rmElemIds.push_back(elem->GetID());
7205           }
7206           else {
7207             rmElemIds.push_back(elem->GetID());
7208           }
7209
7210         }
7211         else if (elem->GetType() == SMDSAbs_Volume) {
7212           // Polyhedral volume
7213           if (nbUniqueNodes < 4) {
7214             rmElemIds.push_back(elem->GetID());
7215           }
7216           else {
7217             // each face has to be analyzed in order to check volume validity
7218             const SMDS_VtkVolume* aPolyedre =
7219               dynamic_cast<const SMDS_VtkVolume*>( elem );
7220             if (aPolyedre) {
7221               int nbFaces = aPolyedre->NbFaces();
7222
7223               vector<const SMDS_MeshNode *> poly_nodes;
7224               vector<int> quantities;
7225
7226               for (int iface = 1; iface <= nbFaces; iface++) {
7227                 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7228                 vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
7229
7230                 for (int inode = 1; inode <= nbFaceNodes; inode++) {
7231                   const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
7232                   TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
7233                   if (nnIt != nodeNodeMap.end()) { // faceNode sticks
7234                     faceNode = (*nnIt).second;
7235                   }
7236                   faceNodes[inode - 1] = faceNode;
7237                 }
7238
7239                 SimplifyFace(faceNodes, poly_nodes, quantities);
7240               }
7241
7242               if (quantities.size() > 3) {
7243                 // to be done: remove coincident faces
7244               }
7245
7246               if (quantities.size() > 3)
7247                 {
7248                   MESSAGE("ChangeElementNodes MergeNodes Polyhedron");
7249                   //aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
7250                   const SMDS_MeshElement* newElem = 0;
7251                   newElem = aMesh->AddPolyhedralVolume(poly_nodes, quantities);
7252                   myLastCreatedElems.Append(newElem);
7253                   if ( aShapeId && newElem )
7254                     aMesh->SetMeshElementOnShape( newElem, aShapeId );
7255                   rmElemIds.push_back(elem->GetID());
7256                 }
7257             }
7258             else {
7259               rmElemIds.push_back(elem->GetID());
7260             }
7261           }
7262         }
7263         else {
7264         }
7265
7266         continue;
7267       } // poly element
7268
7269       // Regular elements
7270       // TODO not all the possible cases are solved. Find something more generic?
7271       switch ( nbNodes ) {
7272       case 2: ///////////////////////////////////// EDGE
7273         isOk = false; break;
7274       case 3: ///////////////////////////////////// TRIANGLE
7275         isOk = false; break;
7276       case 4:
7277         if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
7278           isOk = false;
7279         else { //////////////////////////////////// QUADRANGLE
7280           if ( nbUniqueNodes < 3 )
7281             isOk = false;
7282           else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
7283             isOk = false; // opposite nodes stick
7284           //MESSAGE("isOk " << isOk);
7285         }
7286         break;
7287       case 6: ///////////////////////////////////// PENTAHEDRON
7288         if ( nbUniqueNodes == 4 ) {
7289           // ---------------------------------> tetrahedron
7290           if (nbRepl == 3 &&
7291               iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
7292             // all top nodes stick: reverse a bottom
7293             uniqueNodes[ 0 ] = curNodes [ 1 ];
7294             uniqueNodes[ 1 ] = curNodes [ 0 ];
7295           }
7296           else if (nbRepl == 3 &&
7297                    iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
7298             // all bottom nodes stick: set a top before
7299             uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
7300             uniqueNodes[ 0 ] = curNodes [ 3 ];
7301             uniqueNodes[ 1 ] = curNodes [ 4 ];
7302             uniqueNodes[ 2 ] = curNodes [ 5 ];
7303           }
7304           else if (nbRepl == 4 &&
7305                    iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
7306             // a lateral face turns into a line: reverse a bottom
7307             uniqueNodes[ 0 ] = curNodes [ 1 ];
7308             uniqueNodes[ 1 ] = curNodes [ 0 ];
7309           }
7310           else
7311             isOk = false;
7312         }
7313         else if ( nbUniqueNodes == 5 ) {
7314           // PENTAHEDRON --------------------> 2 tetrahedrons
7315           if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
7316             // a bottom node sticks with a linked top one
7317             // 1.
7318             SMDS_MeshElement* newElem =
7319               aMesh->AddVolume(curNodes[ 3 ],
7320                                curNodes[ 4 ],
7321                                curNodes[ 5 ],
7322                                curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
7323             myLastCreatedElems.Append(newElem);
7324             if ( aShapeId )
7325               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7326             // 2. : reverse a bottom
7327             uniqueNodes[ 0 ] = curNodes [ 1 ];
7328             uniqueNodes[ 1 ] = curNodes [ 0 ];
7329             nbUniqueNodes = 4;
7330           }
7331           else
7332             isOk = false;
7333         }
7334         else
7335           isOk = false;
7336         break;
7337       case 8: {
7338         if(elem->IsQuadratic()) { // Quadratic quadrangle
7339           //   1    5    2
7340           //    +---+---+
7341           //    |       |
7342           //    |       |
7343           //   4+       +6
7344           //    |       |
7345           //    |       |
7346           //    +---+---+
7347           //   0    7    3
7348           isOk = false;
7349           if(nbRepl==2) {
7350             MESSAGE("nbRepl=2: " << iRepl[0] << " " << iRepl[1]);
7351           }
7352           if(nbRepl==3) {
7353             MESSAGE("nbRepl=3: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2]);
7354             nbUniqueNodes = 6;
7355             if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
7356               uniqueNodes[0] = curNodes[0];
7357               uniqueNodes[1] = curNodes[2];
7358               uniqueNodes[2] = curNodes[3];
7359               uniqueNodes[3] = curNodes[5];
7360               uniqueNodes[4] = curNodes[6];
7361               uniqueNodes[5] = curNodes[7];
7362               isOk = true;
7363             }
7364             if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
7365               uniqueNodes[0] = curNodes[0];
7366               uniqueNodes[1] = curNodes[1];
7367               uniqueNodes[2] = curNodes[2];
7368               uniqueNodes[3] = curNodes[4];
7369               uniqueNodes[4] = curNodes[5];
7370               uniqueNodes[5] = curNodes[6];
7371               isOk = true;
7372             }
7373             if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
7374               uniqueNodes[0] = curNodes[1];
7375               uniqueNodes[1] = curNodes[2];
7376               uniqueNodes[2] = curNodes[3];
7377               uniqueNodes[3] = curNodes[5];
7378               uniqueNodes[4] = curNodes[6];
7379               uniqueNodes[5] = curNodes[0];
7380               isOk = true;
7381             }
7382             if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
7383               uniqueNodes[0] = curNodes[0];
7384               uniqueNodes[1] = curNodes[1];
7385               uniqueNodes[2] = curNodes[3];
7386               uniqueNodes[3] = curNodes[4];
7387               uniqueNodes[4] = curNodes[6];
7388               uniqueNodes[5] = curNodes[7];
7389               isOk = true;
7390             }
7391             if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
7392               uniqueNodes[0] = curNodes[0];
7393               uniqueNodes[1] = curNodes[2];
7394               uniqueNodes[2] = curNodes[3];
7395               uniqueNodes[3] = curNodes[1];
7396               uniqueNodes[4] = curNodes[6];
7397               uniqueNodes[5] = curNodes[7];
7398               isOk = true;
7399             }
7400             if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
7401               uniqueNodes[0] = curNodes[0];
7402               uniqueNodes[1] = curNodes[1];
7403               uniqueNodes[2] = curNodes[2];
7404               uniqueNodes[3] = curNodes[4];
7405               uniqueNodes[4] = curNodes[5];
7406               uniqueNodes[5] = curNodes[7];
7407               isOk = true;
7408             }
7409             if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
7410               uniqueNodes[0] = curNodes[0];
7411               uniqueNodes[1] = curNodes[1];
7412               uniqueNodes[2] = curNodes[3];
7413               uniqueNodes[3] = curNodes[4];
7414               uniqueNodes[4] = curNodes[2];
7415               uniqueNodes[5] = curNodes[7];
7416               isOk = true;
7417             }
7418             if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
7419               uniqueNodes[0] = curNodes[0];
7420               uniqueNodes[1] = curNodes[1];
7421               uniqueNodes[2] = curNodes[2];
7422               uniqueNodes[3] = curNodes[4];
7423               uniqueNodes[4] = curNodes[5];
7424               uniqueNodes[5] = curNodes[3];
7425               isOk = true;
7426             }
7427           }
7428           if(nbRepl==4) {
7429             MESSAGE("nbRepl=4: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2] << " " << iRepl[3]);
7430           }
7431           if(nbRepl==5) {
7432             MESSAGE("nbRepl=5: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2] << " " << iRepl[3] << " " << iRepl[4]);
7433           }
7434           break;
7435         }
7436         //////////////////////////////////// HEXAHEDRON
7437         isOk = false;
7438         SMDS_VolumeTool hexa (elem);
7439         hexa.SetExternalNormal();
7440         if ( nbUniqueNodes == 4 && nbRepl == 4 ) {
7441           //////////////////////// HEX ---> 1 tetrahedron
7442           for ( int iFace = 0; iFace < 6; iFace++ ) {
7443             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7444             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7445                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7446                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7447               // one face turns into a point ...
7448               int iOppFace = hexa.GetOppFaceIndex( iFace );
7449               ind = hexa.GetFaceNodesIndices( iOppFace );
7450               int nbStick = 0;
7451               for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
7452                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7453                   nbStick++;
7454               }
7455               if ( nbStick == 1 ) {
7456                 // ... and the opposite one - into a triangle.
7457                 // set a top node
7458                 ind = hexa.GetFaceNodesIndices( iFace );
7459                 uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
7460                 isOk = true;
7461               }
7462               break;
7463             }
7464           }
7465         }
7466         else if ( nbUniqueNodes == 6 && nbRepl == 2 ) {
7467           //////////////////////// HEX ---> 1 prism
7468           int nbTria = 0, iTria[3];
7469           const int *ind; // indices of face nodes
7470           // look for triangular faces
7471           for ( int iFace = 0; iFace < 6 && nbTria < 3; iFace++ ) {
7472             ind = hexa.GetFaceNodesIndices( iFace );
7473             TIDSortedNodeSet faceNodes;
7474             for ( iCur = 0; iCur < 4; iCur++ )
7475               faceNodes.insert( curNodes[ind[iCur]] );
7476             if ( faceNodes.size() == 3 )
7477               iTria[ nbTria++ ] = iFace;
7478           }
7479           // check if triangles are opposite
7480           if ( nbTria == 2 && iTria[0] == hexa.GetOppFaceIndex( iTria[1] ))
7481           {
7482             isOk = true;
7483             // set nodes of the bottom triangle
7484             ind = hexa.GetFaceNodesIndices( iTria[ 0 ]);
7485             vector<int> indB;
7486             for ( iCur = 0; iCur < 4; iCur++ )
7487               if ( ind[iCur] != iRepl[0] && ind[iCur] != iRepl[1])
7488                 indB.push_back( ind[iCur] );
7489             if ( !hexa.IsForward() )
7490               std::swap( indB[0], indB[2] );
7491             for ( iCur = 0; iCur < 3; iCur++ )
7492               uniqueNodes[ iCur ] = curNodes[indB[iCur]];
7493             // set nodes of the top triangle
7494             const int *indT = hexa.GetFaceNodesIndices( iTria[ 1 ]);
7495             for ( iCur = 0; iCur < 3; ++iCur )
7496               for ( int j = 0; j < 4; ++j )
7497                 if ( hexa.IsLinked( indB[ iCur ], indT[ j ] ))
7498                 {
7499                   uniqueNodes[ iCur + 3 ] = curNodes[ indT[ j ]];
7500                   break;
7501                 }
7502           }
7503           break;
7504         }
7505         else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
7506           //////////////////// HEXAHEDRON ---> 2 tetrahedrons
7507           for ( int iFace = 0; iFace < 6; iFace++ ) {
7508             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7509             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7510                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7511                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7512               // one face turns into a point ...
7513               int iOppFace = hexa.GetOppFaceIndex( iFace );
7514               ind = hexa.GetFaceNodesIndices( iOppFace );
7515               int nbStick = 0;
7516               iUnique = 2;  // reverse a tetrahedron 1 bottom
7517               for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
7518                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7519                   nbStick++;
7520                 else if ( iUnique >= 0 )
7521                   uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7522               }
7523               if ( nbStick == 0 ) {
7524                 // ... and the opposite one is a quadrangle
7525                 // set a top node
7526                 const int* indTop = hexa.GetFaceNodesIndices( iFace );
7527                 uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
7528                 nbUniqueNodes = 4;
7529                 // tetrahedron 2
7530                 SMDS_MeshElement* newElem =
7531                   aMesh->AddVolume(curNodes[ind[ 0 ]],
7532                                    curNodes[ind[ 3 ]],
7533                                    curNodes[ind[ 2 ]],
7534                                    curNodes[indTop[ 0 ]]);
7535                 myLastCreatedElems.Append(newElem);
7536                 if ( aShapeId )
7537                   aMesh->SetMeshElementOnShape( newElem, aShapeId );
7538                 isOk = true;
7539               }
7540               break;
7541             }
7542           }
7543         }
7544         else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
7545           ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
7546           // find indices of quad and tri faces
7547           int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
7548           for ( iFace = 0; iFace < 6; iFace++ ) {
7549             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7550             nodeSet.clear();
7551             for ( iCur = 0; iCur < 4; iCur++ )
7552               nodeSet.insert( curNodes[ind[ iCur ]] );
7553             nbUniqueNodes = nodeSet.size();
7554             if ( nbUniqueNodes == 3 )
7555               iTriFace[ nbTri++ ] = iFace;
7556             else if ( nbUniqueNodes == 4 )
7557               iQuadFace[ nbQuad++ ] = iFace;
7558           }
7559           if (nbQuad == 2 && nbTri == 4 &&
7560               hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
7561             // 2 opposite quadrangles stuck with a diagonal;
7562             // sample groups of merged indices: (0-4)(2-6)
7563             // --------------------------------------------> 2 tetrahedrons
7564             const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
7565             const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
7566             int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
7567             if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
7568                 curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
7569               // stuck with 0-2 diagonal
7570               i0  = ind1[ 3 ];
7571               i1d = ind1[ 0 ];
7572               i2  = ind1[ 1 ];
7573               i3d = ind1[ 2 ];
7574               i0t = ind2[ 1 ];
7575               i2t = ind2[ 3 ];
7576             }
7577             else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
7578                      curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
7579               // stuck with 1-3 diagonal
7580               i0  = ind1[ 0 ];
7581               i1d = ind1[ 1 ];
7582               i2  = ind1[ 2 ];
7583               i3d = ind1[ 3 ];
7584               i0t = ind2[ 0 ];
7585               i2t = ind2[ 1 ];
7586             }
7587             else {
7588               ASSERT(0);
7589             }
7590             // tetrahedron 1
7591             uniqueNodes[ 0 ] = curNodes [ i0 ];
7592             uniqueNodes[ 1 ] = curNodes [ i1d ];
7593             uniqueNodes[ 2 ] = curNodes [ i3d ];
7594             uniqueNodes[ 3 ] = curNodes [ i0t ];
7595             nbUniqueNodes = 4;
7596             // tetrahedron 2
7597             SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
7598                                                          curNodes[ i2 ],
7599                                                          curNodes[ i3d ],
7600                                                          curNodes[ i2t ]);
7601             myLastCreatedElems.Append(newElem);
7602             if ( aShapeId )
7603               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7604             isOk = true;
7605           }
7606           else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
7607                    ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
7608             // --------------------------------------------> prism
7609             // find 2 opposite triangles
7610             nbUniqueNodes = 6;
7611             for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
7612               if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
7613                 // find indices of kept and replaced nodes
7614                 // and fill unique nodes of 2 opposite triangles
7615                 const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
7616                 const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
7617                 const SMDS_MeshNode** hexanodes = hexa.GetNodes();
7618                 // fill unique nodes
7619                 iUnique = 0;
7620                 isOk = true;
7621                 for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
7622                   const SMDS_MeshNode* n     = curNodes[ind1[ iCur ]];
7623                   const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
7624                   if ( n == nInit ) {
7625                     // iCur of a linked node of the opposite face (make normals co-directed):
7626                     int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
7627                     // check that correspondent corners of triangles are linked
7628                     if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
7629                       isOk = false;
7630                     else {
7631                       uniqueNodes[ iUnique ] = n;
7632                       uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
7633                       iUnique++;
7634                     }
7635                   }
7636                 }
7637                 break;
7638               }
7639             }
7640           }
7641         } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
7642         else
7643         {
7644           MESSAGE("MergeNodes() removes hexahedron "<< elem);
7645         }
7646         break;
7647       } // HEXAHEDRON
7648
7649       default:
7650         isOk = false;
7651       } // switch ( nbNodes )
7652
7653     } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
7654
7655     if ( isOk ) { // the elem remains valid after sticking nodes
7656       if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume)
7657       {
7658         // Change nodes of polyedre
7659         const SMDS_VtkVolume* aPolyedre =
7660           dynamic_cast<const SMDS_VtkVolume*>( elem );
7661         if (aPolyedre) {
7662           int nbFaces = aPolyedre->NbFaces();
7663
7664           vector<const SMDS_MeshNode *> poly_nodes;
7665           vector<int> quantities (nbFaces);
7666
7667           for (int iface = 1; iface <= nbFaces; iface++) {
7668             int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7669             quantities[iface - 1] = nbFaceNodes;
7670
7671             for (inode = 1; inode <= nbFaceNodes; inode++) {
7672               const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
7673
7674               TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
7675               if (nnIt != nodeNodeMap.end()) { // curNode sticks
7676                 curNode = (*nnIt).second;
7677               }
7678               poly_nodes.push_back(curNode);
7679             }
7680           }
7681           aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
7682         }
7683       }
7684       else // replace non-polyhedron elements
7685       {
7686         const SMDSAbs_ElementType etyp = elem->GetType();
7687         const int elemId               = elem->GetID();
7688         const bool isPoly              = (elem->GetEntityType() == SMDSEntity_Polygon);
7689         uniqueNodes.resize(nbUniqueNodes);
7690
7691         SMESHDS_SubMesh * sm = aShapeId > 0 ? aMesh->MeshElements(aShapeId) : 0;
7692
7693         aMesh->RemoveFreeElement(elem, sm, /*fromGroups=*/false);
7694         SMDS_MeshElement* newElem = this->AddElement(uniqueNodes, etyp, isPoly, elemId);
7695         if ( sm && newElem )
7696           sm->AddElement( newElem );
7697         if ( elem != newElem )
7698           ReplaceElemInGroups( elem, newElem, aMesh );
7699       }
7700     }
7701     else {
7702       // Remove invalid regular element or invalid polygon
7703       rmElemIds.push_back( elem->GetID() );
7704     }
7705
7706   } // loop on elements
7707
7708   // Remove bad elements, then equal nodes (order important)
7709
7710   Remove( rmElemIds, false );
7711   Remove( rmNodeIds, true );
7712
7713 }
7714
7715
7716 // ========================================================
7717 // class   : SortableElement
7718 // purpose : allow sorting elements basing on their nodes
7719 // ========================================================
7720 class SortableElement : public set <const SMDS_MeshElement*>
7721 {
7722 public:
7723
7724   SortableElement( const SMDS_MeshElement* theElem )
7725   {
7726     myElem = theElem;
7727     SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
7728     while ( nodeIt->more() )
7729       this->insert( nodeIt->next() );
7730   }
7731
7732   const SMDS_MeshElement* Get() const
7733   { return myElem; }
7734
7735   void Set(const SMDS_MeshElement* e) const
7736   { myElem = e; }
7737
7738
7739 private:
7740   mutable const SMDS_MeshElement* myElem;
7741 };
7742
7743 //=======================================================================
7744 //function : FindEqualElements
7745 //purpose  : Return list of group of elements built on the same nodes.
7746 //           Search among theElements or in the whole mesh if theElements is empty
7747 //=======================================================================
7748 void SMESH_MeshEditor::FindEqualElements(set<const SMDS_MeshElement*> & theElements,
7749                                          TListOfListOfElementsID &      theGroupsOfElementsID)
7750 {
7751   myLastCreatedElems.Clear();
7752   myLastCreatedNodes.Clear();
7753
7754   typedef set<const SMDS_MeshElement*> TElemsSet;
7755   typedef map< SortableElement, int > TMapOfNodeSet;
7756   typedef list<int> TGroupOfElems;
7757
7758   TElemsSet elems;
7759   if ( theElements.empty() )
7760   { // get all elements in the mesh
7761     SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
7762     while ( eIt->more() )
7763       elems.insert( elems.end(), eIt->next());
7764   }
7765   else
7766     elems = theElements;
7767
7768   vector< TGroupOfElems > arrayOfGroups;
7769   TGroupOfElems groupOfElems;
7770   TMapOfNodeSet mapOfNodeSet;
7771
7772   TElemsSet::iterator elemIt = elems.begin();
7773   for ( int i = 0, j=0; elemIt != elems.end(); ++elemIt, ++j ) {
7774     const SMDS_MeshElement* curElem = *elemIt;
7775     SortableElement SE(curElem);
7776     int ind = -1;
7777     // check uniqueness
7778     pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
7779     if( !(pp.second) ) {
7780       TMapOfNodeSet::iterator& itSE = pp.first;
7781       ind = (*itSE).second;
7782       arrayOfGroups[ind].push_back(curElem->GetID());
7783     }
7784     else {
7785       groupOfElems.clear();
7786       groupOfElems.push_back(curElem->GetID());
7787       arrayOfGroups.push_back(groupOfElems);
7788       i++;
7789     }
7790   }
7791
7792   vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
7793   for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
7794     groupOfElems = *groupIt;
7795     if ( groupOfElems.size() > 1 ) {
7796       groupOfElems.sort();
7797       theGroupsOfElementsID.push_back(groupOfElems);
7798     }
7799   }
7800 }
7801
7802 //=======================================================================
7803 //function : MergeElements
7804 //purpose  : In each given group, substitute all elements by the first one.
7805 //=======================================================================
7806
7807 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
7808 {
7809   myLastCreatedElems.Clear();
7810   myLastCreatedNodes.Clear();
7811
7812   typedef list<int> TListOfIDs;
7813   TListOfIDs rmElemIds; // IDs of elems to remove
7814
7815   SMESHDS_Mesh* aMesh = GetMeshDS();
7816
7817   TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
7818   while ( groupsIt != theGroupsOfElementsID.end() ) {
7819     TListOfIDs& aGroupOfElemID = *groupsIt;
7820     aGroupOfElemID.sort();
7821     int elemIDToKeep = aGroupOfElemID.front();
7822     const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
7823     aGroupOfElemID.pop_front();
7824     TListOfIDs::iterator idIt = aGroupOfElemID.begin();
7825     while ( idIt != aGroupOfElemID.end() ) {
7826       int elemIDToRemove = *idIt;
7827       const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
7828       // add the kept element in groups of removed one (PAL15188)
7829       AddToSameGroups( elemToKeep, elemToRemove, aMesh );
7830       rmElemIds.push_back( elemIDToRemove );
7831       ++idIt;
7832     }
7833     ++groupsIt;
7834   }
7835
7836   Remove( rmElemIds, false );
7837 }
7838
7839 //=======================================================================
7840 //function : MergeEqualElements
7841 //purpose  : Remove all but one of elements built on the same nodes.
7842 //=======================================================================
7843
7844 void SMESH_MeshEditor::MergeEqualElements()
7845 {
7846   set<const SMDS_MeshElement*> aMeshElements; /* empty input -
7847                                                  to merge equal elements in the whole mesh */
7848   TListOfListOfElementsID aGroupsOfElementsID;
7849   FindEqualElements(aMeshElements, aGroupsOfElementsID);
7850   MergeElements(aGroupsOfElementsID);
7851 }
7852
7853 //=======================================================================
7854 //function : FindFaceInSet
7855 //purpose  : Return a face having linked nodes n1 and n2 and which is
7856 //           - not in avoidSet,
7857 //           - in elemSet provided that !elemSet.empty()
7858 //           i1 and i2 optionally returns indices of n1 and n2
7859 //=======================================================================
7860
7861 const SMDS_MeshElement*
7862 SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode*    n1,
7863                                 const SMDS_MeshNode*    n2,
7864                                 const TIDSortedElemSet& elemSet,
7865                                 const TIDSortedElemSet& avoidSet,
7866                                 int*                    n1ind,
7867                                 int*                    n2ind)
7868
7869 {
7870   int i1, i2;
7871   const SMDS_MeshElement* face = 0;
7872
7873   SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face);
7874   //MESSAGE("n1->GetInverseElementIterator(SMDSAbs_Face) " << invElemIt);
7875   while ( invElemIt->more() && !face ) // loop on inverse faces of n1
7876   {
7877     //MESSAGE("in while ( invElemIt->more() && !face )");
7878     const SMDS_MeshElement* elem = invElemIt->next();
7879     if (avoidSet.count( elem ))
7880       continue;
7881     if ( !elemSet.empty() && !elemSet.count( elem ))
7882       continue;
7883     // index of n1
7884     i1 = elem->GetNodeIndex( n1 );
7885     // find a n2 linked to n1
7886     int nbN = elem->IsQuadratic() ? elem->NbNodes()/2 : elem->NbNodes();
7887     for ( int di = -1; di < 2 && !face; di += 2 )
7888     {
7889       i2 = (i1+di+nbN) % nbN;
7890       if ( elem->GetNode( i2 ) == n2 )
7891         face = elem;
7892     }
7893     if ( !face && elem->IsQuadratic())
7894     {
7895       // analysis for quadratic elements using all nodes
7896       const SMDS_VtkFace* F =
7897         dynamic_cast<const SMDS_VtkFace*>(elem);
7898       if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
7899       // use special nodes iterator
7900       SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
7901       const SMDS_MeshNode* prevN = cast2Node( anIter->next() );
7902       for ( i1 = -1, i2 = 0; anIter->more() && !face; i1++, i2++ )
7903       {
7904         const SMDS_MeshNode* n = cast2Node( anIter->next() );
7905         if ( n1 == prevN && n2 == n )
7906         {
7907           face = elem;
7908         }
7909         else if ( n2 == prevN && n1 == n )
7910         {
7911           face = elem; swap( i1, i2 );
7912         }
7913         prevN = n;
7914       }
7915     }
7916   }
7917   if ( n1ind ) *n1ind = i1;
7918   if ( n2ind ) *n2ind = i2;
7919   return face;
7920 }
7921
7922 //=======================================================================
7923 //function : findAdjacentFace
7924 //purpose  :
7925 //=======================================================================
7926
7927 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
7928                                                 const SMDS_MeshNode* n2,
7929                                                 const SMDS_MeshElement* elem)
7930 {
7931   TIDSortedElemSet elemSet, avoidSet;
7932   if ( elem )
7933     avoidSet.insert ( elem );
7934   return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet );
7935 }
7936
7937 //=======================================================================
7938 //function : FindFreeBorder
7939 //purpose  :
7940 //=======================================================================
7941
7942 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
7943
7944 bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode*             theFirstNode,
7945                                        const SMDS_MeshNode*             theSecondNode,
7946                                        const SMDS_MeshNode*             theLastNode,
7947                                        list< const SMDS_MeshNode* > &   theNodes,
7948                                        list< const SMDS_MeshElement* >& theFaces)
7949 {
7950   if ( !theFirstNode || !theSecondNode )
7951     return false;
7952   // find border face between theFirstNode and theSecondNode
7953   const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
7954   if ( !curElem )
7955     return false;
7956
7957   theFaces.push_back( curElem );
7958   theNodes.push_back( theFirstNode );
7959   theNodes.push_back( theSecondNode );
7960
7961   //vector<const SMDS_MeshNode*> nodes;
7962   const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
7963   TIDSortedElemSet foundElems;
7964   bool needTheLast = ( theLastNode != 0 );
7965
7966   while ( nStart != theLastNode ) {
7967     if ( nStart == theFirstNode )
7968       return !needTheLast;
7969
7970     // find all free border faces sharing form nStart
7971
7972     list< const SMDS_MeshElement* > curElemList;
7973     list< const SMDS_MeshNode* > nStartList;
7974     SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
7975     while ( invElemIt->more() ) {
7976       const SMDS_MeshElement* e = invElemIt->next();
7977       if ( e == curElem || foundElems.insert( e ).second ) {
7978         // get nodes
7979         int iNode = 0, nbNodes = e->NbNodes();
7980         //const SMDS_MeshNode* nodes[nbNodes+1];
7981         vector<const SMDS_MeshNode*> nodes(nbNodes+1);
7982
7983         if(e->IsQuadratic()) {
7984           const SMDS_VtkFace* F =
7985             dynamic_cast<const SMDS_VtkFace*>(e);
7986           if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
7987           // use special nodes iterator
7988           SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
7989           while( anIter->more() ) {
7990             nodes[ iNode++ ] = cast2Node(anIter->next());
7991           }
7992         }
7993         else {
7994           SMDS_ElemIteratorPtr nIt = e->nodesIterator();
7995           while ( nIt->more() )
7996             nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
7997         }
7998         nodes[ iNode ] = nodes[ 0 ];
7999         // check 2 links
8000         for ( iNode = 0; iNode < nbNodes; iNode++ )
8001           if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
8002                (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
8003               ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
8004           {
8005             nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
8006             curElemList.push_back( e );
8007           }
8008       }
8009     }
8010     // analyse the found
8011
8012     int nbNewBorders = curElemList.size();
8013     if ( nbNewBorders == 0 ) {
8014       // no free border furthermore
8015       return !needTheLast;
8016     }
8017     else if ( nbNewBorders == 1 ) {
8018       // one more element found
8019       nIgnore = nStart;
8020       nStart = nStartList.front();
8021       curElem = curElemList.front();
8022       theFaces.push_back( curElem );
8023       theNodes.push_back( nStart );
8024     }
8025     else {
8026       // several continuations found
8027       list< const SMDS_MeshElement* >::iterator curElemIt;
8028       list< const SMDS_MeshNode* >::iterator nStartIt;
8029       // check if one of them reached the last node
8030       if ( needTheLast ) {
8031         for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
8032              curElemIt!= curElemList.end();
8033              curElemIt++, nStartIt++ )
8034           if ( *nStartIt == theLastNode ) {
8035             theFaces.push_back( *curElemIt );
8036             theNodes.push_back( *nStartIt );
8037             return true;
8038           }
8039       }
8040       // find the best free border by the continuations
8041       list<const SMDS_MeshNode*>    contNodes[ 2 ], *cNL;
8042       list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
8043       for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
8044            curElemIt!= curElemList.end();
8045            curElemIt++, nStartIt++ )
8046       {
8047         cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
8048         cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
8049         // find one more free border
8050         if ( ! FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
8051           cNL->clear();
8052           cFL->clear();
8053         }
8054         else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
8055           // choice: clear a worse one
8056           int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
8057           int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
8058           contNodes[ iWorse ].clear();
8059           contFaces[ iWorse ].clear();
8060         }
8061       }
8062       if ( contNodes[0].empty() && contNodes[1].empty() )
8063         return false;
8064
8065       // append the best free border
8066       cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
8067       cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
8068       theNodes.pop_back(); // remove nIgnore
8069       theNodes.pop_back(); // remove nStart
8070       theFaces.pop_back(); // remove curElem
8071       list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
8072       list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
8073       for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
8074       for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
8075       return true;
8076
8077     } // several continuations found
8078   } // while ( nStart != theLastNode )
8079
8080   return true;
8081 }
8082
8083 //=======================================================================
8084 //function : CheckFreeBorderNodes
8085 //purpose  : Return true if the tree nodes are on a free border
8086 //=======================================================================
8087
8088 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
8089                                             const SMDS_MeshNode* theNode2,
8090                                             const SMDS_MeshNode* theNode3)
8091 {
8092   list< const SMDS_MeshNode* > nodes;
8093   list< const SMDS_MeshElement* > faces;
8094   return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
8095 }
8096
8097 //=======================================================================
8098 //function : SewFreeBorder
8099 //purpose  :
8100 //=======================================================================
8101
8102 SMESH_MeshEditor::Sew_Error
8103 SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
8104                                  const SMDS_MeshNode* theBordSecondNode,
8105                                  const SMDS_MeshNode* theBordLastNode,
8106                                  const SMDS_MeshNode* theSideFirstNode,
8107                                  const SMDS_MeshNode* theSideSecondNode,
8108                                  const SMDS_MeshNode* theSideThirdNode,
8109                                  const bool           theSideIsFreeBorder,
8110                                  const bool           toCreatePolygons,
8111                                  const bool           toCreatePolyedrs)
8112 {
8113   myLastCreatedElems.Clear();
8114   myLastCreatedNodes.Clear();
8115
8116   MESSAGE("::SewFreeBorder()");
8117   Sew_Error aResult = SEW_OK;
8118
8119   // ====================================
8120   //    find side nodes and elements
8121   // ====================================
8122
8123   list< const SMDS_MeshNode* > nSide[ 2 ];
8124   list< const SMDS_MeshElement* > eSide[ 2 ];
8125   list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
8126   list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
8127
8128   // Free border 1
8129   // --------------
8130   if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
8131                       nSide[0], eSide[0])) {
8132     MESSAGE(" Free Border 1 not found " );
8133     aResult = SEW_BORDER1_NOT_FOUND;
8134   }
8135   if (theSideIsFreeBorder) {
8136     // Free border 2
8137     // --------------
8138     if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
8139                         nSide[1], eSide[1])) {
8140       MESSAGE(" Free Border 2 not found " );
8141       aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
8142     }
8143   }
8144   if ( aResult != SEW_OK )
8145     return aResult;
8146
8147   if (!theSideIsFreeBorder) {
8148     // Side 2
8149     // --------------
8150
8151     // -------------------------------------------------------------------------
8152     // Algo:
8153     // 1. If nodes to merge are not coincident, move nodes of the free border
8154     //    from the coord sys defined by the direction from the first to last
8155     //    nodes of the border to the correspondent sys of the side 2
8156     // 2. On the side 2, find the links most co-directed with the correspondent
8157     //    links of the free border
8158     // -------------------------------------------------------------------------
8159
8160     // 1. Since sewing may break if there are volumes to split on the side 2,
8161     //    we wont move nodes but just compute new coordinates for them
8162     typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
8163     TNodeXYZMap nBordXYZ;
8164     list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
8165     list< const SMDS_MeshNode* >::iterator nBordIt;
8166
8167     gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
8168     gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
8169     gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
8170     gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
8171     double tol2 = 1.e-8;
8172     gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
8173     if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
8174       // Need node movement.
8175
8176       // find X and Z axes to create trsf
8177       gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
8178       gp_Vec X = Zs ^ Zb;
8179       if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
8180         // Zb || Zs
8181         X = gp_Ax2( gp::Origin(), Zb ).XDirection();
8182
8183       // coord systems
8184       gp_Ax3 toBordAx( Pb1, Zb, X );
8185       gp_Ax3 fromSideAx( Ps1, Zs, X );
8186       gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
8187       // set trsf
8188       gp_Trsf toBordSys, fromSide2Sys;
8189       toBordSys.SetTransformation( toBordAx );
8190       fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
8191       fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
8192
8193       // move
8194       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8195         const SMDS_MeshNode* n = *nBordIt;
8196         gp_XYZ xyz( n->X(),n->Y(),n->Z() );
8197         toBordSys.Transforms( xyz );
8198         fromSide2Sys.Transforms( xyz );
8199         nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
8200       }
8201     }
8202     else {
8203       // just insert nodes XYZ in the nBordXYZ map
8204       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8205         const SMDS_MeshNode* n = *nBordIt;
8206         nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
8207       }
8208     }
8209
8210     // 2. On the side 2, find the links most co-directed with the correspondent
8211     //    links of the free border
8212
8213     list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
8214     list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
8215     sideNodes.push_back( theSideFirstNode );
8216
8217     bool hasVolumes = false;
8218     LinkID_Gen aLinkID_Gen( GetMeshDS() );
8219     set<long> foundSideLinkIDs, checkedLinkIDs;
8220     SMDS_VolumeTool volume;
8221     //const SMDS_MeshNode* faceNodes[ 4 ];
8222
8223     const SMDS_MeshNode*    sideNode;
8224     const SMDS_MeshElement* sideElem;
8225     const SMDS_MeshNode* prevSideNode = theSideFirstNode;
8226     const SMDS_MeshNode* prevBordNode = theBordFirstNode;
8227     nBordIt = bordNodes.begin();
8228     nBordIt++;
8229     // border node position and border link direction to compare with
8230     gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
8231     gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
8232     // choose next side node by link direction or by closeness to
8233     // the current border node:
8234     bool searchByDir = ( *nBordIt != theBordLastNode );
8235     do {
8236       // find the next node on the Side 2
8237       sideNode = 0;
8238       double maxDot = -DBL_MAX, minDist = DBL_MAX;
8239       long linkID;
8240       checkedLinkIDs.clear();
8241       gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
8242
8243       // loop on inverse elements of current node (prevSideNode) on the Side 2
8244       SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
8245       while ( invElemIt->more() )
8246       {
8247         const SMDS_MeshElement* elem = invElemIt->next();
8248         // prepare data for a loop on links coming to prevSideNode, of a face or a volume
8249         int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
8250         vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
8251         bool isVolume = volume.Set( elem );
8252         const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
8253         if ( isVolume ) // --volume
8254           hasVolumes = true;
8255         else if ( elem->GetType()==SMDSAbs_Face ) { // --face
8256           // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
8257           if(elem->IsQuadratic()) {
8258             const SMDS_VtkFace* F =
8259               dynamic_cast<const SMDS_VtkFace*>(elem);
8260             if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8261             // use special nodes iterator
8262             SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8263             while( anIter->more() ) {
8264               nodes[ iNode ] = cast2Node(anIter->next());
8265               if ( nodes[ iNode++ ] == prevSideNode )
8266                 iPrevNode = iNode - 1;
8267             }
8268           }
8269           else {
8270             SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
8271             while ( nIt->more() ) {
8272               nodes[ iNode ] = cast2Node( nIt->next() );
8273               if ( nodes[ iNode++ ] == prevSideNode )
8274                 iPrevNode = iNode - 1;
8275             }
8276           }
8277           // there are 2 links to check
8278           nbNodes = 2;
8279         }
8280         else // --edge
8281           continue;
8282         // loop on links, to be precise, on the second node of links
8283         for ( iNode = 0; iNode < nbNodes; iNode++ ) {
8284           const SMDS_MeshNode* n = nodes[ iNode ];
8285           if ( isVolume ) {
8286             if ( !volume.IsLinked( n, prevSideNode ))
8287               continue;
8288           }
8289           else {
8290             if ( iNode ) // a node before prevSideNode
8291               n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
8292             else         // a node after prevSideNode
8293               n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
8294           }
8295           // check if this link was already used
8296           long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
8297           bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
8298           if (!isJustChecked &&
8299               foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
8300           {
8301             // test a link geometrically
8302             gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
8303             bool linkIsBetter = false;
8304             double dot = 0.0, dist = 0.0;
8305             if ( searchByDir ) { // choose most co-directed link
8306               dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
8307               linkIsBetter = ( dot > maxDot );
8308             }
8309             else { // choose link with the node closest to bordPos
8310               dist = ( nextXYZ - bordPos ).SquareModulus();
8311               linkIsBetter = ( dist < minDist );
8312             }
8313             if ( linkIsBetter ) {
8314               maxDot = dot;
8315               minDist = dist;
8316               linkID = iLink;
8317               sideNode = n;
8318               sideElem = elem;
8319             }
8320           }
8321         }
8322       } // loop on inverse elements of prevSideNode
8323
8324       if ( !sideNode ) {
8325         MESSAGE(" Cant find path by links of the Side 2 ");
8326         return SEW_BAD_SIDE_NODES;
8327       }
8328       sideNodes.push_back( sideNode );
8329       sideElems.push_back( sideElem );
8330       foundSideLinkIDs.insert ( linkID );
8331       prevSideNode = sideNode;
8332
8333       if ( *nBordIt == theBordLastNode )
8334         searchByDir = false;
8335       else {
8336         // find the next border link to compare with
8337         gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
8338         searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8339         // move to next border node if sideNode is before forward border node (bordPos)
8340         while ( *nBordIt != theBordLastNode && !searchByDir ) {
8341           prevBordNode = *nBordIt;
8342           nBordIt++;
8343           bordPos = nBordXYZ[ *nBordIt ];
8344           bordDir = bordPos - nBordXYZ[ prevBordNode ];
8345           searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8346         }
8347       }
8348     }
8349     while ( sideNode != theSideSecondNode );
8350
8351     if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
8352       MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
8353       return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
8354     }
8355   } // end nodes search on the side 2
8356
8357   // ============================
8358   // sew the border to the side 2
8359   // ============================
8360
8361   int nbNodes[]  = { nSide[0].size(), nSide[1].size() };
8362   int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
8363
8364   TListOfListOfNodes nodeGroupsToMerge;
8365   if ( nbNodes[0] == nbNodes[1] ||
8366        ( theSideIsFreeBorder && !theSideThirdNode)) {
8367
8368     // all nodes are to be merged
8369
8370     for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
8371          nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
8372          nIt[0]++, nIt[1]++ )
8373     {
8374       nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8375       nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
8376       nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
8377     }
8378   }
8379   else {
8380
8381     // insert new nodes into the border and the side to get equal nb of segments
8382
8383     // get normalized parameters of nodes on the borders
8384     //double param[ 2 ][ maxNbNodes ];
8385     double* param[ 2 ];
8386     param[0] = new double [ maxNbNodes ];
8387     param[1] = new double [ maxNbNodes ];
8388     int iNode, iBord;
8389     for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8390       list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
8391       list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
8392       const SMDS_MeshNode* nPrev = *nIt;
8393       double bordLength = 0;
8394       for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
8395         const SMDS_MeshNode* nCur = *nIt;
8396         gp_XYZ segment (nCur->X() - nPrev->X(),
8397                         nCur->Y() - nPrev->Y(),
8398                         nCur->Z() - nPrev->Z());
8399         double segmentLen = segment.Modulus();
8400         bordLength += segmentLen;
8401         param[ iBord ][ iNode ] = bordLength;
8402         nPrev = nCur;
8403       }
8404       // normalize within [0,1]
8405       for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
8406         param[ iBord ][ iNode ] /= bordLength;
8407       }
8408     }
8409
8410     // loop on border segments
8411     const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
8412     int i[ 2 ] = { 0, 0 };
8413     nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
8414     nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
8415
8416     TElemOfNodeListMap insertMap;
8417     TElemOfNodeListMap::iterator insertMapIt;
8418     // insertMap is
8419     // key:   elem to insert nodes into
8420     // value: 2 nodes to insert between + nodes to be inserted
8421     do {
8422       bool next[ 2 ] = { false, false };
8423
8424       // find min adjacent segment length after sewing
8425       double nextParam = 10., prevParam = 0;
8426       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8427         if ( i[ iBord ] + 1 < nbNodes[ iBord ])
8428           nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
8429         if ( i[ iBord ] > 0 )
8430           prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
8431       }
8432       double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8433       double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8434       double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
8435
8436       // choose to insert or to merge nodes
8437       double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
8438       if ( Abs( du ) <= minSegLen * 0.2 ) {
8439         // merge
8440         // ------
8441         nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8442         const SMDS_MeshNode* n0 = *nIt[0];
8443         const SMDS_MeshNode* n1 = *nIt[1];
8444         nodeGroupsToMerge.back().push_back( n1 );
8445         nodeGroupsToMerge.back().push_back( n0 );
8446         // position of node of the border changes due to merge
8447         param[ 0 ][ i[0] ] += du;
8448         // move n1 for the sake of elem shape evaluation during insertion.
8449         // n1 will be removed by MergeNodes() anyway
8450         const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
8451         next[0] = next[1] = true;
8452       }
8453       else {
8454         // insert
8455         // ------
8456         int intoBord = ( du < 0 ) ? 0 : 1;
8457         const SMDS_MeshElement* elem = *eIt[ intoBord ];
8458         const SMDS_MeshNode*    n1   = nPrev[ intoBord ];
8459         const SMDS_MeshNode*    n2   = *nIt[ intoBord ];
8460         const SMDS_MeshNode*    nIns = *nIt[ 1 - intoBord ];
8461         if ( intoBord == 1 ) {
8462           // move node of the border to be on a link of elem of the side
8463           gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
8464           gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
8465           double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
8466           gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
8467           GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
8468         }
8469         insertMapIt = insertMap.find( elem );
8470         bool notFound = ( insertMapIt == insertMap.end() );
8471         bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
8472         if ( otherLink ) {
8473           // insert into another link of the same element:
8474           // 1. perform insertion into the other link of the elem
8475           list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8476           const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
8477           const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
8478           InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
8479           // 2. perform insertion into the link of adjacent faces
8480           while (true) {
8481             const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
8482             if ( adjElem )
8483               InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
8484             else
8485               break;
8486           }
8487           if (toCreatePolyedrs) {
8488             // perform insertion into the links of adjacent volumes
8489             UpdateVolumes(n12, n22, nodeList);
8490           }
8491           // 3. find an element appeared on n1 and n2 after the insertion
8492           insertMap.erase( elem );
8493           elem = findAdjacentFace( n1, n2, 0 );
8494         }
8495         if ( notFound || otherLink ) {
8496           // add element and nodes of the side into the insertMap
8497           insertMapIt = insertMap.insert
8498             ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
8499           (*insertMapIt).second.push_back( n1 );
8500           (*insertMapIt).second.push_back( n2 );
8501         }
8502         // add node to be inserted into elem
8503         (*insertMapIt).second.push_back( nIns );
8504         next[ 1 - intoBord ] = true;
8505       }
8506
8507       // go to the next segment
8508       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8509         if ( next[ iBord ] ) {
8510           if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
8511             eIt[ iBord ]++;
8512           nPrev[ iBord ] = *nIt[ iBord ];
8513           nIt[ iBord ]++; i[ iBord ]++;
8514         }
8515       }
8516     }
8517     while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
8518
8519     // perform insertion of nodes into elements
8520
8521     for (insertMapIt = insertMap.begin();
8522          insertMapIt != insertMap.end();
8523          insertMapIt++ )
8524     {
8525       const SMDS_MeshElement* elem = (*insertMapIt).first;
8526       list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8527       const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
8528       const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
8529
8530       InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
8531
8532       if ( !theSideIsFreeBorder ) {
8533         // look for and insert nodes into the faces adjacent to elem
8534         while (true) {
8535           const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
8536           if ( adjElem )
8537             InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
8538           else
8539             break;
8540         }
8541       }
8542       if (toCreatePolyedrs) {
8543         // perform insertion into the links of adjacent volumes
8544         UpdateVolumes(n1, n2, nodeList);
8545       }
8546     }
8547
8548     delete param[0];
8549     delete param[1];
8550   } // end: insert new nodes
8551
8552   MergeNodes ( nodeGroupsToMerge );
8553
8554   return aResult;
8555 }
8556
8557 //=======================================================================
8558 //function : InsertNodesIntoLink
8559 //purpose  : insert theNodesToInsert into theFace between theBetweenNode1
8560 //           and theBetweenNode2 and split theElement
8561 //=======================================================================
8562
8563 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement*     theFace,
8564                                            const SMDS_MeshNode*        theBetweenNode1,
8565                                            const SMDS_MeshNode*        theBetweenNode2,
8566                                            list<const SMDS_MeshNode*>& theNodesToInsert,
8567                                            const bool                  toCreatePoly)
8568 {
8569   if ( theFace->GetType() != SMDSAbs_Face ) return;
8570
8571   // find indices of 2 link nodes and of the rest nodes
8572   int iNode = 0, il1, il2, i3, i4;
8573   il1 = il2 = i3 = i4 = -1;
8574   //const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
8575   vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
8576
8577   if(theFace->IsQuadratic()) {
8578     const SMDS_VtkFace* F =
8579       dynamic_cast<const SMDS_VtkFace*>(theFace);
8580     if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8581     // use special nodes iterator
8582     SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8583     while( anIter->more() ) {
8584       const SMDS_MeshNode* n = cast2Node(anIter->next());
8585       if ( n == theBetweenNode1 )
8586         il1 = iNode;
8587       else if ( n == theBetweenNode2 )
8588         il2 = iNode;
8589       else if ( i3 < 0 )
8590         i3 = iNode;
8591       else
8592         i4 = iNode;
8593       nodes[ iNode++ ] = n;
8594     }
8595   }
8596   else {
8597     SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8598     while ( nodeIt->more() ) {
8599       const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8600       if ( n == theBetweenNode1 )
8601         il1 = iNode;
8602       else if ( n == theBetweenNode2 )
8603         il2 = iNode;
8604       else if ( i3 < 0 )
8605         i3 = iNode;
8606       else
8607         i4 = iNode;
8608       nodes[ iNode++ ] = n;
8609     }
8610   }
8611   if ( il1 < 0 || il2 < 0 || i3 < 0 )
8612     return ;
8613
8614   // arrange link nodes to go one after another regarding the face orientation
8615   bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
8616   list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
8617   if ( reverse ) {
8618     iNode = il1;
8619     il1 = il2;
8620     il2 = iNode;
8621     aNodesToInsert.reverse();
8622   }
8623   // check that not link nodes of a quadrangles are in good order
8624   int nbFaceNodes = theFace->NbNodes();
8625   if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
8626     iNode = i3;
8627     i3 = i4;
8628     i4 = iNode;
8629   }
8630
8631   if (toCreatePoly || theFace->IsPoly()) {
8632
8633     iNode = 0;
8634     vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
8635
8636     // add nodes of face up to first node of link
8637     bool isFLN = false;
8638
8639     if(theFace->IsQuadratic()) {
8640       const SMDS_VtkFace* F =
8641         dynamic_cast<const SMDS_VtkFace*>(theFace);
8642       if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8643       // use special nodes iterator
8644       SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8645       while( anIter->more()  && !isFLN ) {
8646         const SMDS_MeshNode* n = cast2Node(anIter->next());
8647         poly_nodes[iNode++] = n;
8648         if (n == nodes[il1]) {
8649           isFLN = true;
8650         }
8651       }
8652       // add nodes to insert
8653       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8654       for (; nIt != aNodesToInsert.end(); nIt++) {
8655         poly_nodes[iNode++] = *nIt;
8656       }
8657       // add nodes of face starting from last node of link
8658       while ( anIter->more() ) {
8659         poly_nodes[iNode++] = cast2Node(anIter->next());
8660       }
8661     }
8662     else {
8663       SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8664       while ( nodeIt->more() && !isFLN ) {
8665         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8666         poly_nodes[iNode++] = n;
8667         if (n == nodes[il1]) {
8668           isFLN = true;
8669         }
8670       }
8671       // add nodes to insert
8672       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8673       for (; nIt != aNodesToInsert.end(); nIt++) {
8674         poly_nodes[iNode++] = *nIt;
8675       }
8676       // add nodes of face starting from last node of link
8677       while ( nodeIt->more() ) {
8678         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8679         poly_nodes[iNode++] = n;
8680       }
8681     }
8682
8683     // edit or replace the face
8684     SMESHDS_Mesh *aMesh = GetMeshDS();
8685
8686     if (theFace->IsPoly()) {
8687       aMesh->ChangePolygonNodes(theFace, poly_nodes);
8688     }
8689     else {
8690       int aShapeId = FindShape( theFace );
8691
8692       SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
8693       myLastCreatedElems.Append(newElem);
8694       if ( aShapeId && newElem )
8695         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8696
8697       aMesh->RemoveElement(theFace);
8698     }
8699     return;
8700   }
8701
8702   SMESHDS_Mesh *aMesh = GetMeshDS();
8703   if( !theFace->IsQuadratic() ) {
8704
8705     // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
8706     int nbLinkNodes = 2 + aNodesToInsert.size();
8707     //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
8708     vector<const SMDS_MeshNode*> linkNodes( nbLinkNodes );
8709     linkNodes[ 0 ] = nodes[ il1 ];
8710     linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
8711     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8712     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8713       linkNodes[ iNode++ ] = *nIt;
8714     }
8715     // decide how to split a quadrangle: compare possible variants
8716     // and choose which of splits to be a quadrangle
8717     int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
8718     if ( nbFaceNodes == 3 ) {
8719       iBestQuad = nbSplits;
8720       i4 = i3;
8721     }
8722     else if ( nbFaceNodes == 4 ) {
8723       SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
8724       double aBestRate = DBL_MAX;
8725       for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
8726         i1 = 0; i2 = 1;
8727         double aBadRate = 0;
8728         // evaluate elements quality
8729         for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
8730           if ( iSplit == iQuad ) {
8731             SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
8732                                    linkNodes[ i2++ ],
8733                                    nodes[ i3 ],
8734                                    nodes[ i4 ]);
8735             aBadRate += getBadRate( &quad, aCrit );
8736           }
8737           else {
8738             SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
8739                                    linkNodes[ i2++ ],
8740                                    nodes[ iSplit < iQuad ? i4 : i3 ]);
8741             aBadRate += getBadRate( &tria, aCrit );
8742           }
8743         }
8744         // choice
8745         if ( aBadRate < aBestRate ) {
8746           iBestQuad = iQuad;
8747           aBestRate = aBadRate;
8748         }
8749       }
8750     }
8751
8752     // create new elements
8753     int aShapeId = FindShape( theFace );
8754
8755     i1 = 0; i2 = 1;
8756     for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
8757       SMDS_MeshElement* newElem = 0;
8758       if ( iSplit == iBestQuad )
8759         newElem = aMesh->AddFace (linkNodes[ i1++ ],
8760                                   linkNodes[ i2++ ],
8761                                   nodes[ i3 ],
8762                                   nodes[ i4 ]);
8763       else
8764         newElem = aMesh->AddFace (linkNodes[ i1++ ],
8765                                   linkNodes[ i2++ ],
8766                                   nodes[ iSplit < iBestQuad ? i4 : i3 ]);
8767       myLastCreatedElems.Append(newElem);
8768       if ( aShapeId && newElem )
8769         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8770     }
8771
8772     // change nodes of theFace
8773     const SMDS_MeshNode* newNodes[ 4 ];
8774     newNodes[ 0 ] = linkNodes[ i1 ];
8775     newNodes[ 1 ] = linkNodes[ i2 ];
8776     newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
8777     newNodes[ 3 ] = nodes[ i4 ];
8778     //aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
8779     const SMDS_MeshElement* newElem = 0;
8780     if (iSplit == iBestQuad)
8781       newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2], newNodes[3] );
8782     else
8783       newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2] );
8784     myLastCreatedElems.Append(newElem);
8785     if ( aShapeId && newElem )
8786       aMesh->SetMeshElementOnShape( newElem, aShapeId );
8787 } // end if(!theFace->IsQuadratic())
8788   else { // theFace is quadratic
8789     // we have to split theFace on simple triangles and one simple quadrangle
8790     int tmp = il1/2;
8791     int nbshift = tmp*2;
8792     // shift nodes in nodes[] by nbshift
8793     int i,j;
8794     for(i=0; i<nbshift; i++) {
8795       const SMDS_MeshNode* n = nodes[0];
8796       for(j=0; j<nbFaceNodes-1; j++) {
8797         nodes[j] = nodes[j+1];
8798       }
8799       nodes[nbFaceNodes-1] = n;
8800     }
8801     il1 = il1 - nbshift;
8802     // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
8803     //   n0      n1     n2    n0      n1     n2
8804     //     +-----+-----+        +-----+-----+
8805     //      \         /         |           |
8806     //       \       /          |           |
8807     //      n5+     +n3       n7+           +n3
8808     //         \   /            |           |
8809     //          \ /             |           |
8810     //           +              +-----+-----+
8811     //           n4           n6      n5     n4
8812
8813     // create new elements
8814     int aShapeId = FindShape( theFace );
8815
8816     int n1,n2,n3;
8817     if(nbFaceNodes==6) { // quadratic triangle
8818       SMDS_MeshElement* newElem =
8819         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
8820       myLastCreatedElems.Append(newElem);
8821       if ( aShapeId && newElem )
8822         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8823       if(theFace->IsMediumNode(nodes[il1])) {
8824         // create quadrangle
8825         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
8826         myLastCreatedElems.Append(newElem);
8827         if ( aShapeId && newElem )
8828           aMesh->SetMeshElementOnShape( newElem, aShapeId );
8829         n1 = 1;
8830         n2 = 2;
8831         n3 = 3;
8832       }
8833       else {
8834         // create quadrangle
8835         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
8836         myLastCreatedElems.Append(newElem);
8837         if ( aShapeId && newElem )
8838           aMesh->SetMeshElementOnShape( newElem, aShapeId );
8839         n1 = 0;
8840         n2 = 1;
8841         n3 = 5;
8842       }
8843     }
8844     else { // nbFaceNodes==8 - quadratic quadrangle
8845       SMDS_MeshElement* newElem =
8846         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
8847       myLastCreatedElems.Append(newElem);
8848       if ( aShapeId && newElem )
8849         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8850       newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
8851       myLastCreatedElems.Append(newElem);
8852       if ( aShapeId && newElem )
8853         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8854       newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
8855       myLastCreatedElems.Append(newElem);
8856       if ( aShapeId && newElem )
8857         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8858       if(theFace->IsMediumNode(nodes[il1])) {
8859         // create quadrangle
8860         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
8861         myLastCreatedElems.Append(newElem);
8862         if ( aShapeId && newElem )
8863           aMesh->SetMeshElementOnShape( newElem, aShapeId );
8864         n1 = 1;
8865         n2 = 2;
8866         n3 = 3;
8867       }
8868       else {
8869         // create quadrangle
8870         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
8871         myLastCreatedElems.Append(newElem);
8872         if ( aShapeId && newElem )
8873           aMesh->SetMeshElementOnShape( newElem, aShapeId );
8874         n1 = 0;
8875         n2 = 1;
8876         n3 = 7;
8877       }
8878     }
8879     // create needed triangles using n1,n2,n3 and inserted nodes
8880     int nbn = 2 + aNodesToInsert.size();
8881     //const SMDS_MeshNode* aNodes[nbn];
8882     vector<const SMDS_MeshNode*> aNodes(nbn);
8883     aNodes[0] = nodes[n1];
8884     aNodes[nbn-1] = nodes[n2];
8885     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8886     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8887       aNodes[iNode++] = *nIt;
8888     }
8889     for(i=1; i<nbn; i++) {
8890       SMDS_MeshElement* newElem =
8891         aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
8892       myLastCreatedElems.Append(newElem);
8893       if ( aShapeId && newElem )
8894         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8895     }
8896   }
8897   // remove old face
8898   aMesh->RemoveElement(theFace);
8899 }
8900
8901 //=======================================================================
8902 //function : UpdateVolumes
8903 //purpose  :
8904 //=======================================================================
8905 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode*        theBetweenNode1,
8906                                       const SMDS_MeshNode*        theBetweenNode2,
8907                                       list<const SMDS_MeshNode*>& theNodesToInsert)
8908 {
8909   myLastCreatedElems.Clear();
8910   myLastCreatedNodes.Clear();
8911
8912   SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
8913   while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
8914     const SMDS_MeshElement* elem = invElemIt->next();
8915
8916     // check, if current volume has link theBetweenNode1 - theBetweenNode2
8917     SMDS_VolumeTool aVolume (elem);
8918     if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
8919       continue;
8920
8921     // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
8922     int iface, nbFaces = aVolume.NbFaces();
8923     vector<const SMDS_MeshNode *> poly_nodes;
8924     vector<int> quantities (nbFaces);
8925
8926     for (iface = 0; iface < nbFaces; iface++) {
8927       int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
8928       // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
8929       const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
8930
8931       for (int inode = 0; inode < nbFaceNodes; inode++) {
8932         poly_nodes.push_back(faceNodes[inode]);
8933
8934         if (nbInserted == 0) {
8935           if (faceNodes[inode] == theBetweenNode1) {
8936             if (faceNodes[inode + 1] == theBetweenNode2) {
8937               nbInserted = theNodesToInsert.size();
8938
8939               // add nodes to insert
8940               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
8941               for (; nIt != theNodesToInsert.end(); nIt++) {
8942                 poly_nodes.push_back(*nIt);
8943               }
8944             }
8945           }
8946           else if (faceNodes[inode] == theBetweenNode2) {
8947             if (faceNodes[inode + 1] == theBetweenNode1) {
8948               nbInserted = theNodesToInsert.size();
8949
8950               // add nodes to insert in reversed order
8951               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
8952               nIt--;
8953               for (; nIt != theNodesToInsert.begin(); nIt--) {
8954                 poly_nodes.push_back(*nIt);
8955               }
8956               poly_nodes.push_back(*nIt);
8957             }
8958           }
8959           else {
8960           }
8961         }
8962       }
8963       quantities[iface] = nbFaceNodes + nbInserted;
8964     }
8965
8966     // Replace or update the volume
8967     SMESHDS_Mesh *aMesh = GetMeshDS();
8968
8969     if (elem->IsPoly()) {
8970       aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
8971
8972     }
8973     else {
8974       int aShapeId = FindShape( elem );
8975
8976       SMDS_MeshElement* newElem =
8977         aMesh->AddPolyhedralVolume(poly_nodes, quantities);
8978       myLastCreatedElems.Append(newElem);
8979       if (aShapeId && newElem)
8980         aMesh->SetMeshElementOnShape(newElem, aShapeId);
8981
8982       aMesh->RemoveElement(elem);
8983     }
8984   }
8985 }
8986
8987 namespace
8988 {
8989   //================================================================================
8990   /*!
8991    * \brief Transform any volume into data of SMDSEntity_Polyhedra
8992    */
8993   //================================================================================
8994
8995   void volumeToPolyhedron( const SMDS_MeshElement*         elem,
8996                            vector<const SMDS_MeshNode *> & nodes,
8997                            vector<int> &                   nbNodeInFaces )
8998   {
8999     nodes.clear();
9000     nbNodeInFaces.clear();
9001     SMDS_VolumeTool vTool ( elem );
9002     for ( int iF = 0; iF < vTool.NbFaces(); ++iF )
9003     {
9004       const SMDS_MeshNode** fNodes = vTool.GetFaceNodes( iF );
9005       nodes.insert( nodes.end(), fNodes, fNodes + vTool.NbFaceNodes( iF ));
9006       nbNodeInFaces.push_back( vTool.NbFaceNodes( iF ));
9007     }
9008   }
9009 }
9010
9011 //=======================================================================
9012 /*!
9013  * \brief Convert elements contained in a submesh to quadratic
9014  * \return int - nb of checked elements
9015  */
9016 //=======================================================================
9017
9018 int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh *   theSm,
9019                                              SMESH_MesherHelper& theHelper,
9020                                              const bool          theForce3d)
9021 {
9022   int nbElem = 0;
9023   if( !theSm ) return nbElem;
9024
9025   vector<int> nbNodeInFaces;
9026   vector<const SMDS_MeshNode *> nodes;
9027   SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
9028   while(ElemItr->more())
9029   {
9030     nbElem++;
9031     const SMDS_MeshElement* elem = ElemItr->next();
9032     if( !elem || elem->IsQuadratic() ) continue;
9033
9034     // get elem data needed to re-create it
9035     //
9036     const int id                        = elem->GetID();
9037     const int nbNodes                   = elem->NbNodes();
9038     const SMDSAbs_ElementType aType     = elem->GetType();
9039     const SMDSAbs_EntityType  aGeomType = elem->GetEntityType();
9040     nodes.assign(elem->begin_nodes(), elem->end_nodes());
9041     if ( aGeomType == SMDSEntity_Polyhedra )
9042       nbNodeInFaces = static_cast<const SMDS_VtkVolume* >( elem )->GetQuantities();
9043     else if ( aGeomType == SMDSEntity_Hexagonal_Prism )
9044       volumeToPolyhedron( elem, nodes, nbNodeInFaces );
9045
9046     // remove a linear element
9047     GetMeshDS()->RemoveFreeElement(elem, theSm, /*fromGroups=*/false);
9048
9049     const SMDS_MeshElement* NewElem = 0;
9050
9051     switch( aType )
9052     {
9053     case SMDSAbs_Edge :
9054       {
9055         NewElem = theHelper.AddEdge(nodes[0], nodes[1], id, theForce3d);
9056         break;
9057       }
9058     case SMDSAbs_Face :
9059       {
9060         switch(nbNodes)
9061         {
9062         case 3:
9063           NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
9064           break;
9065         case 4:
9066           NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9067           break;
9068         default:
9069           NewElem = theHelper.AddPolygonalFace(nodes, id, theForce3d);
9070           continue;
9071         }
9072         break;
9073       }
9074     case SMDSAbs_Volume :
9075       {
9076         switch( aGeomType )
9077         {
9078         case SMDSEntity_Tetra:
9079           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9080           break;
9081         case SMDSEntity_Pyramid:
9082           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], id, theForce3d);
9083           break;
9084         case SMDSEntity_Penta:
9085           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], nodes[5], id, theForce3d);
9086           break;
9087         case SMDSEntity_Hexa:
9088           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9089                                         nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9090           break;
9091         case SMDSEntity_Hexagonal_Prism:
9092         default:
9093           NewElem = theHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9094         }
9095         break;
9096       }
9097     default :
9098       continue;
9099     }
9100     ReplaceElemInGroups( elem, NewElem, GetMeshDS());
9101     if( NewElem )
9102       theSm->AddElement( NewElem );
9103   }
9104   return nbElem;
9105 }
9106
9107 //=======================================================================
9108 //function : ConvertToQuadratic
9109 //purpose  :
9110 //=======================================================================
9111
9112 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
9113 {
9114   SMESHDS_Mesh* meshDS = GetMeshDS();
9115
9116   SMESH_MesherHelper aHelper(*myMesh);
9117   aHelper.SetIsQuadratic( true );
9118
9119   int nbCheckedElems = 0;
9120   if ( myMesh->HasShapeToMesh() )
9121   {
9122     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9123     {
9124       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9125       while ( smIt->more() ) {
9126         SMESH_subMesh* sm = smIt->next();
9127         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
9128           aHelper.SetSubShape( sm->GetSubShape() );
9129           nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
9130         }
9131       }
9132     }
9133   }
9134   int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
9135   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9136   {
9137     SMESHDS_SubMesh *smDS = 0;
9138     SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
9139     while(aEdgeItr->more())
9140     {
9141       const SMDS_MeshEdge* edge = aEdgeItr->next();
9142       if(edge && !edge->IsQuadratic())
9143       {
9144         int id = edge->GetID();
9145         //MESSAGE("edge->GetID() " << id);
9146         const SMDS_MeshNode* n1 = edge->GetNode(0);
9147         const SMDS_MeshNode* n2 = edge->GetNode(1);
9148
9149         meshDS->RemoveFreeElement(edge, smDS, /*fromGroups=*/false);
9150
9151         const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
9152         ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
9153       }
9154     }
9155     SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
9156     while(aFaceItr->more())
9157     {
9158       const SMDS_MeshFace* face = aFaceItr->next();
9159       if(!face || face->IsQuadratic() ) continue;
9160
9161       const int id = face->GetID();
9162       const SMDSAbs_EntityType type = face->GetEntityType();
9163       vector<const SMDS_MeshNode *> nodes ( face->begin_nodes(), face->end_nodes());
9164
9165       meshDS->RemoveFreeElement(face, smDS, /*fromGroups=*/false);
9166
9167       SMDS_MeshFace * NewFace = 0;
9168       switch( type )
9169       {
9170       case SMDSEntity_Triangle:
9171         NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
9172         break;
9173       case SMDSEntity_Quadrangle:
9174         NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9175         break;
9176       default:
9177         NewFace = aHelper.AddPolygonalFace(nodes, id, theForce3d);
9178       }
9179       ReplaceElemInGroups( face, NewFace, GetMeshDS());
9180     }
9181     vector<int> nbNodeInFaces;
9182     SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
9183     while(aVolumeItr->more())
9184     {
9185       const SMDS_MeshVolume* volume = aVolumeItr->next();
9186       if(!volume || volume->IsQuadratic() ) continue;
9187
9188       const int id = volume->GetID();
9189       const SMDSAbs_EntityType type = volume->GetEntityType();
9190       vector<const SMDS_MeshNode *> nodes (volume->begin_nodes(), volume->end_nodes());
9191       if ( type == SMDSEntity_Polyhedra )
9192         nbNodeInFaces = static_cast<const SMDS_VtkVolume* >(volume)->GetQuantities();
9193       else if ( type == SMDSEntity_Hexagonal_Prism )
9194         volumeToPolyhedron( volume, nodes, nbNodeInFaces );
9195
9196       meshDS->RemoveFreeElement(volume, smDS, /*fromGroups=*/false);
9197
9198       SMDS_MeshVolume * NewVolume = 0;
9199       switch ( type )
9200       {
9201       case SMDSEntity_Tetra:
9202         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d );
9203         break;
9204       case SMDSEntity_Hexa:
9205         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9206                                       nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9207         break;
9208       case SMDSEntity_Pyramid:
9209         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9210                                       nodes[3], nodes[4], id, theForce3d);
9211         break;
9212       case SMDSEntity_Penta:
9213         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9214                                       nodes[3], nodes[4], nodes[5], id, theForce3d);
9215         break;
9216       case SMDSEntity_Hexagonal_Prism:
9217       default:
9218         NewVolume = aHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9219       }
9220       ReplaceElemInGroups(volume, NewVolume, meshDS);
9221     }
9222   }
9223
9224   if ( !theForce3d )
9225   { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
9226     aHelper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
9227     aHelper.FixQuadraticElements();
9228   }
9229 }
9230
9231 //================================================================================
9232 /*!
9233  * \brief Makes given elements quadratic
9234  *  \param theForce3d - if true, the medium nodes will be placed in the middle of link
9235  *  \param theElements - elements to make quadratic 
9236  */
9237 //================================================================================
9238
9239 void SMESH_MeshEditor::ConvertToQuadratic(const bool        theForce3d,
9240                                           TIDSortedElemSet& theElements)
9241 {
9242   if ( theElements.empty() ) return;
9243
9244   // we believe that all theElements are of the same type
9245   const SMDSAbs_ElementType elemType = (*theElements.begin())->GetType();
9246   
9247   // get all nodes shared by theElements
9248   TIDSortedNodeSet allNodes;
9249   TIDSortedElemSet::iterator eIt = theElements.begin();
9250   for ( ; eIt != theElements.end(); ++eIt )
9251     allNodes.insert( (*eIt)->begin_nodes(), (*eIt)->end_nodes() );
9252
9253   // complete theElements with elements of lower dim whose all nodes are in allNodes
9254
9255   TIDSortedElemSet quadAdjacentElems    [ SMDSAbs_NbElementTypes ]; // quadratic adjacent elements
9256   TIDSortedElemSet checkedAdjacentElems [ SMDSAbs_NbElementTypes ];
9257   TIDSortedNodeSet::iterator nIt = allNodes.begin();
9258   for ( ; nIt != allNodes.end(); ++nIt )
9259   {
9260     const SMDS_MeshNode* n = *nIt;
9261     SMDS_ElemIteratorPtr invIt = n->GetInverseElementIterator();
9262     while ( invIt->more() )
9263     {
9264       const SMDS_MeshElement* e = invIt->next();
9265       if ( e->IsQuadratic() )
9266       {
9267         quadAdjacentElems[ e->GetType() ].insert( e );
9268         continue;
9269       }
9270       if ( e->GetType() >= elemType )
9271       {
9272         continue; // same type of more complex linear element
9273       }
9274
9275       if ( !checkedAdjacentElems[ e->GetType() ].insert( e ).second )
9276         continue; // e is already checked
9277
9278       // check nodes
9279       bool allIn = true;
9280       SMDS_ElemIteratorPtr nodeIt = e->nodesIterator();
9281       while ( nodeIt->more() && allIn )
9282         allIn = allNodes.count( cast2Node( nodeIt->next() ));
9283       if ( allIn )
9284         theElements.insert(e );
9285     }
9286   }
9287
9288   SMESH_MesherHelper helper(*myMesh);
9289   helper.SetIsQuadratic( true );
9290
9291   // add links of quadratic adjacent elements to the helper
9292
9293   if ( !quadAdjacentElems[SMDSAbs_Edge].empty() )
9294     for ( eIt  = quadAdjacentElems[SMDSAbs_Edge].begin();
9295           eIt != quadAdjacentElems[SMDSAbs_Edge].end(); ++eIt )
9296     {
9297       helper.AddTLinks( static_cast< const SMDS_MeshEdge*> (*eIt) );
9298     }
9299   if ( !quadAdjacentElems[SMDSAbs_Face].empty() )
9300     for ( eIt  = quadAdjacentElems[SMDSAbs_Face].begin();
9301           eIt != quadAdjacentElems[SMDSAbs_Face].end(); ++eIt )
9302     {
9303       helper.AddTLinks( static_cast< const SMDS_MeshFace*> (*eIt) );
9304     }
9305   if ( !quadAdjacentElems[SMDSAbs_Volume].empty() )
9306     for ( eIt  = quadAdjacentElems[SMDSAbs_Volume].begin();
9307           eIt != quadAdjacentElems[SMDSAbs_Volume].end(); ++eIt )
9308     {
9309       helper.AddTLinks( static_cast< const SMDS_MeshVolume*> (*eIt) );
9310     }
9311
9312   // make quadratic elements instead of linear ones
9313
9314   SMESHDS_Mesh* meshDS = GetMeshDS();
9315   SMESHDS_SubMesh* smDS = 0;
9316   for ( eIt = theElements.begin(); eIt != theElements.end(); ++eIt )
9317   {
9318     const SMDS_MeshElement* elem = *eIt;
9319     if( elem->IsQuadratic() || elem->NbNodes() < 2 || elem->IsPoly() )
9320       continue;
9321
9322     const int id                   = elem->GetID();
9323     const SMDSAbs_ElementType type = elem->GetType();
9324     vector<const SMDS_MeshNode *> nodes ( elem->begin_nodes(), elem->end_nodes());
9325
9326     if ( !smDS || !smDS->Contains( elem ))
9327       smDS = meshDS->MeshElements( elem->getshapeId() );
9328     meshDS->RemoveFreeElement(elem, smDS, /*fromGroups=*/false);
9329
9330     SMDS_MeshElement * newElem = 0;
9331     switch( nodes.size() )
9332     {
9333     case 4: // cases for most frequently used element types go first (for optimization)
9334       if ( type == SMDSAbs_Volume )
9335         newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9336       else
9337         newElem = helper.AddFace  (nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9338       break;
9339     case 8:
9340       newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9341                                  nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9342       break;
9343     case 3:
9344       newElem = helper.AddFace  (nodes[0], nodes[1], nodes[2], id, theForce3d);
9345       break;
9346     case 2:
9347       newElem = helper.AddEdge(nodes[0], nodes[1], id, theForce3d);
9348       break;
9349     case 5:
9350       newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9351                                  nodes[4], id, theForce3d);
9352       break;
9353     case 6:
9354       newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9355                                  nodes[4], nodes[5], id, theForce3d);
9356       break;
9357     default:;
9358     }
9359     ReplaceElemInGroups( elem, newElem, meshDS);
9360     if( newElem && smDS )
9361       smDS->AddElement( newElem );
9362   }
9363
9364   if ( !theForce3d  && !getenv("NO_FixQuadraticElements"))
9365   { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
9366     helper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
9367     helper.FixQuadraticElements();
9368   }
9369 }
9370
9371 //=======================================================================
9372 /*!
9373  * \brief Convert quadratic elements to linear ones and remove quadratic nodes
9374  * \return int - nb of checked elements
9375  */
9376 //=======================================================================
9377
9378 int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh *    theSm,
9379                                      SMDS_ElemIteratorPtr theItr,
9380                                      const int            theShapeID)
9381 {
9382   int nbElem = 0;
9383   SMESHDS_Mesh* meshDS = GetMeshDS();
9384
9385   while( theItr->more() )
9386   {
9387     const SMDS_MeshElement* elem = theItr->next();
9388     nbElem++;
9389     if( elem && elem->IsQuadratic())
9390     {
9391       int id                    = elem->GetID();
9392       int nbCornerNodes         = elem->NbCornerNodes();
9393       SMDSAbs_ElementType aType = elem->GetType();
9394
9395       vector<const SMDS_MeshNode *> nodes( elem->begin_nodes(), elem->end_nodes() );
9396
9397       //remove a quadratic element
9398       if ( !theSm || !theSm->Contains( elem ))
9399         theSm = meshDS->MeshElements( elem->getshapeId() );
9400       meshDS->RemoveFreeElement( elem, theSm, /*fromGroups=*/false );
9401
9402       // remove medium nodes
9403       for ( unsigned i = nbCornerNodes; i < nodes.size(); ++i )
9404         if ( nodes[i]->NbInverseElements() == 0 )
9405           meshDS->RemoveFreeNode( nodes[i], theSm );
9406
9407       // add a linear element
9408       nodes.resize( nbCornerNodes );
9409       SMDS_MeshElement * newElem = AddElement( nodes, aType, false, id );
9410       ReplaceElemInGroups(elem, newElem, meshDS);
9411       if( theSm && newElem )
9412         theSm->AddElement( newElem );
9413     }
9414   }
9415   return nbElem;
9416 }
9417
9418 //=======================================================================
9419 //function : ConvertFromQuadratic
9420 //purpose  :
9421 //=======================================================================
9422
9423 bool SMESH_MeshEditor::ConvertFromQuadratic()
9424 {
9425   int nbCheckedElems = 0;
9426   if ( myMesh->HasShapeToMesh() )
9427   {
9428     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9429     {
9430       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9431       while ( smIt->more() ) {
9432         SMESH_subMesh* sm = smIt->next();
9433         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
9434           nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
9435       }
9436     }
9437   }
9438
9439   int totalNbElems =
9440     GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
9441   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9442   {
9443     SMESHDS_SubMesh *aSM = 0;
9444     removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
9445   }
9446
9447   return true;
9448 }
9449
9450 namespace
9451 {
9452   //================================================================================
9453   /*!
9454    * \brief Return true if all medium nodes of the element are in the node set
9455    */
9456   //================================================================================
9457
9458   bool allMediumNodesIn(const SMDS_MeshElement* elem, TIDSortedNodeSet& nodeSet )
9459   {
9460     for ( int i = elem->NbCornerNodes(); i < elem->NbNodes(); ++i )
9461       if ( !nodeSet.count( elem->GetNode(i) ))
9462         return false;
9463     return true;
9464   }
9465 }
9466
9467 //================================================================================
9468 /*!
9469  * \brief Makes given elements linear
9470  */
9471 //================================================================================
9472
9473 void SMESH_MeshEditor::ConvertFromQuadratic(TIDSortedElemSet& theElements)
9474 {
9475   if ( theElements.empty() ) return;
9476
9477   // collect IDs of medium nodes of theElements; some of these nodes will be removed
9478   set<int> mediumNodeIDs;
9479   TIDSortedElemSet::iterator eIt = theElements.begin();
9480   for ( ; eIt != theElements.end(); ++eIt )
9481   {
9482     const SMDS_MeshElement* e = *eIt;
9483     for ( int i = e->NbCornerNodes(); i < e->NbNodes(); ++i )
9484       mediumNodeIDs.insert( e->GetNode(i)->GetID() );
9485   }
9486
9487   // replace given elements by linear ones
9488   typedef SMDS_SetIterator<const SMDS_MeshElement*, TIDSortedElemSet::iterator> TSetIterator;
9489   SMDS_ElemIteratorPtr elemIt( new TSetIterator( theElements.begin(), theElements.end() ));
9490   removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
9491
9492   // we need to convert remaining elements whose all medium nodes are in mediumNodeIDs
9493   // except those elements sharing medium nodes of quadratic element whose medium nodes
9494   // are not all in mediumNodeIDs
9495
9496   // get remaining medium nodes
9497   TIDSortedNodeSet mediumNodes;
9498   set<int>::iterator nIdsIt = mediumNodeIDs.begin();
9499   for ( ; nIdsIt != mediumNodeIDs.end(); ++nIdsIt )
9500     if ( const SMDS_MeshNode* n = GetMeshDS()->FindNode( *nIdsIt ))
9501       mediumNodes.insert( mediumNodes.end(), n );
9502
9503   // find more quadratic elements to convert
9504   TIDSortedElemSet moreElemsToConvert;
9505   TIDSortedNodeSet::iterator nIt = mediumNodes.begin();
9506   for ( ; nIt != mediumNodes.end(); ++nIt )
9507   {
9508     SMDS_ElemIteratorPtr invIt = (*nIt)->GetInverseElementIterator();
9509     while ( invIt->more() )
9510     {
9511       const SMDS_MeshElement* e = invIt->next();
9512       if ( e->IsQuadratic() && allMediumNodesIn( e, mediumNodes ))
9513       {
9514         // find a more complex element including e and
9515         // whose medium nodes are not in mediumNodes
9516         bool complexFound = false;
9517         for ( int type = e->GetType() + 1; type < SMDSAbs_0DElement; ++type )
9518         {
9519           SMDS_ElemIteratorPtr invIt2 =
9520             (*nIt)->GetInverseElementIterator( SMDSAbs_ElementType( type ));
9521           while ( invIt2->more() )
9522           {
9523             const SMDS_MeshElement* eComplex = invIt2->next();
9524             if ( eComplex->IsQuadratic() && !allMediumNodesIn( eComplex, mediumNodes))
9525             {
9526               int nbCommonNodes = SMESH_Algo::GetCommonNodes( e, eComplex ).size();
9527               if ( nbCommonNodes == e->NbNodes())
9528               {
9529                 complexFound = true;
9530                 type = SMDSAbs_NbElementTypes; // to quit from the outer loop
9531                 break;
9532               }
9533             }
9534           }
9535         }
9536         if ( !complexFound )
9537           moreElemsToConvert.insert( e );
9538       }
9539     }
9540   }
9541   elemIt = SMDS_ElemIteratorPtr
9542     (new TSetIterator( moreElemsToConvert.begin(), moreElemsToConvert.end() ));
9543   removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
9544 }
9545
9546 //=======================================================================
9547 //function : SewSideElements
9548 //purpose  :
9549 //=======================================================================
9550
9551 SMESH_MeshEditor::Sew_Error
9552 SMESH_MeshEditor::SewSideElements (TIDSortedElemSet&    theSide1,
9553                                    TIDSortedElemSet&    theSide2,
9554                                    const SMDS_MeshNode* theFirstNode1,
9555                                    const SMDS_MeshNode* theFirstNode2,
9556                                    const SMDS_MeshNode* theSecondNode1,
9557                                    const SMDS_MeshNode* theSecondNode2)
9558 {
9559   myLastCreatedElems.Clear();
9560   myLastCreatedNodes.Clear();
9561
9562   MESSAGE ("::::SewSideElements()");
9563   if ( theSide1.size() != theSide2.size() )
9564     return SEW_DIFF_NB_OF_ELEMENTS;
9565
9566   Sew_Error aResult = SEW_OK;
9567   // Algo:
9568   // 1. Build set of faces representing each side
9569   // 2. Find which nodes of the side 1 to merge with ones on the side 2
9570   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9571
9572   // =======================================================================
9573   // 1. Build set of faces representing each side:
9574   // =======================================================================
9575   // a. build set of nodes belonging to faces
9576   // b. complete set of faces: find missing faces whose nodes are in set of nodes
9577   // c. create temporary faces representing side of volumes if correspondent
9578   //    face does not exist
9579
9580   SMESHDS_Mesh* aMesh = GetMeshDS();
9581   // TODO algoritm not OK with vtkUnstructuredGrid: 2 meshes can't share nodes
9582   //SMDS_Mesh aTmpFacesMesh; // try to use the same mesh
9583   set<const SMDS_MeshElement*> faceSet1, faceSet2;
9584   set<const SMDS_MeshElement*> volSet1,  volSet2;
9585   set<const SMDS_MeshNode*>    nodeSet1, nodeSet2;
9586   set<const SMDS_MeshElement*> * faceSetPtr[] = { &faceSet1, &faceSet2 };
9587   set<const SMDS_MeshElement*>  * volSetPtr[] = { &volSet1,  &volSet2  };
9588   set<const SMDS_MeshNode*>    * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
9589   TIDSortedElemSet * elemSetPtr[] = { &theSide1, &theSide2 };
9590   int iSide, iFace, iNode;
9591
9592   list<const SMDS_MeshElement* > tempFaceList;
9593   for ( iSide = 0; iSide < 2; iSide++ ) {
9594     set<const SMDS_MeshNode*>    * nodeSet = nodeSetPtr[ iSide ];
9595     TIDSortedElemSet * elemSet = elemSetPtr[ iSide ];
9596     set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9597     set<const SMDS_MeshElement*> * volSet  = volSetPtr [ iSide ];
9598     set<const SMDS_MeshElement*>::iterator vIt;
9599     TIDSortedElemSet::iterator eIt;
9600     set<const SMDS_MeshNode*>::iterator    nIt;
9601
9602     // check that given nodes belong to given elements
9603     const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
9604     const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
9605     int firstIndex = -1, secondIndex = -1;
9606     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9607       const SMDS_MeshElement* elem = *eIt;
9608       if ( firstIndex  < 0 ) firstIndex  = elem->GetNodeIndex( n1 );
9609       if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
9610       if ( firstIndex > -1 && secondIndex > -1 ) break;
9611     }
9612     if ( firstIndex < 0 || secondIndex < 0 ) {
9613       // we can simply return until temporary faces created
9614       return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
9615     }
9616
9617     // -----------------------------------------------------------
9618     // 1a. Collect nodes of existing faces
9619     //     and build set of face nodes in order to detect missing
9620     //     faces corresponding to sides of volumes
9621     // -----------------------------------------------------------
9622
9623     set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
9624
9625     // loop on the given element of a side
9626     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9627       //const SMDS_MeshElement* elem = *eIt;
9628       const SMDS_MeshElement* elem = *eIt;
9629       if ( elem->GetType() == SMDSAbs_Face ) {
9630         faceSet->insert( elem );
9631         set <const SMDS_MeshNode*> faceNodeSet;
9632         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
9633         while ( nodeIt->more() ) {
9634           const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9635           nodeSet->insert( n );
9636           faceNodeSet.insert( n );
9637         }
9638         setOfFaceNodeSet.insert( faceNodeSet );
9639       }
9640       else if ( elem->GetType() == SMDSAbs_Volume )
9641         volSet->insert( elem );
9642     }
9643     // ------------------------------------------------------------------------------
9644     // 1b. Complete set of faces: find missing faces whose nodes are in set of nodes
9645     // ------------------------------------------------------------------------------
9646
9647     for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9648       SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9649       while ( fIt->more() ) { // loop on faces sharing a node
9650         const SMDS_MeshElement* f = fIt->next();
9651         if ( faceSet->find( f ) == faceSet->end() ) {
9652           // check if all nodes are in nodeSet and
9653           // complete setOfFaceNodeSet if they are
9654           set <const SMDS_MeshNode*> faceNodeSet;
9655           SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9656           bool allInSet = true;
9657           while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9658             const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9659             if ( nodeSet->find( n ) == nodeSet->end() )
9660               allInSet = false;
9661             else
9662               faceNodeSet.insert( n );
9663           }
9664           if ( allInSet ) {
9665             faceSet->insert( f );
9666             setOfFaceNodeSet.insert( faceNodeSet );
9667           }
9668         }
9669       }
9670     }
9671
9672     // -------------------------------------------------------------------------
9673     // 1c. Create temporary faces representing sides of volumes if correspondent
9674     //     face does not exist
9675     // -------------------------------------------------------------------------
9676
9677     if ( !volSet->empty() ) {
9678       //int nodeSetSize = nodeSet->size();
9679
9680       // loop on given volumes
9681       for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
9682         SMDS_VolumeTool vol (*vIt);
9683         // loop on volume faces: find free faces
9684         // --------------------------------------
9685         list<const SMDS_MeshElement* > freeFaceList;
9686         for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
9687           if ( !vol.IsFreeFace( iFace ))
9688             continue;
9689           // check if there is already a face with same nodes in a face set
9690           const SMDS_MeshElement* aFreeFace = 0;
9691           const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
9692           int nbNodes = vol.NbFaceNodes( iFace );
9693           set <const SMDS_MeshNode*> faceNodeSet;
9694           vol.GetFaceNodes( iFace, faceNodeSet );
9695           bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
9696           if ( isNewFace ) {
9697             // no such a face is given but it still can exist, check it
9698             if ( nbNodes == 3 ) {
9699               aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2] );
9700             }
9701             else if ( nbNodes == 4 ) {
9702               aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9703             }
9704             else {
9705               vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9706               aFreeFace = aMesh->FindFace(poly_nodes);
9707             }
9708           }
9709           if ( !aFreeFace ) {
9710             // create a temporary face
9711             if ( nbNodes == 3 ) {
9712               //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
9713               aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2] );
9714             }
9715             else if ( nbNodes == 4 ) {
9716               //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9717               aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9718             }
9719             else {
9720               vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9721               //aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
9722               aFreeFace = aMesh->AddPolygonalFace(poly_nodes);
9723             }
9724           }
9725           if ( aFreeFace ) {
9726             freeFaceList.push_back( aFreeFace );
9727             tempFaceList.push_back( aFreeFace );
9728           }
9729
9730         } // loop on faces of a volume
9731
9732         // choose one of several free faces
9733         // --------------------------------------
9734         if ( freeFaceList.size() > 1 ) {
9735           // choose a face having max nb of nodes shared by other elems of a side
9736           int maxNbNodes = -1/*, nbExcludedFaces = 0*/;
9737           list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
9738           while ( fIt != freeFaceList.end() ) { // loop on free faces
9739             int nbSharedNodes = 0;
9740             SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9741             while ( nodeIt->more() ) { // loop on free face nodes
9742               const SMDS_MeshNode* n =
9743                 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9744               SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
9745               while ( invElemIt->more() ) {
9746                 const SMDS_MeshElement* e = invElemIt->next();
9747                 if ( faceSet->find( e ) != faceSet->end() )
9748                   nbSharedNodes++;
9749                 if ( elemSet->find( e ) != elemSet->end() )
9750                   nbSharedNodes++;
9751               }
9752             }
9753             if ( nbSharedNodes >= maxNbNodes ) {
9754               maxNbNodes = nbSharedNodes;
9755               fIt++;
9756             }
9757             else
9758               freeFaceList.erase( fIt++ ); // here fIt++ occurs before erase
9759           }
9760           if ( freeFaceList.size() > 1 )
9761           {
9762             // could not choose one face, use another way
9763             // choose a face most close to the bary center of the opposite side
9764             gp_XYZ aBC( 0., 0., 0. );
9765             set <const SMDS_MeshNode*> addedNodes;
9766             TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
9767             eIt = elemSet2->begin();
9768             for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
9769               SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
9770               while ( nodeIt->more() ) { // loop on free face nodes
9771                 const SMDS_MeshNode* n =
9772                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9773                 if ( addedNodes.insert( n ).second )
9774                   aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
9775               }
9776             }
9777             aBC /= addedNodes.size();
9778             double minDist = DBL_MAX;
9779             fIt = freeFaceList.begin();
9780             while ( fIt != freeFaceList.end() ) { // loop on free faces
9781               double dist = 0;
9782               SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9783               while ( nodeIt->more() ) { // loop on free face nodes
9784                 const SMDS_MeshNode* n =
9785                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9786                 gp_XYZ p( n->X(),n->Y(),n->Z() );
9787                 dist += ( aBC - p ).SquareModulus();
9788               }
9789               if ( dist < minDist ) {
9790                 minDist = dist;
9791                 freeFaceList.erase( freeFaceList.begin(), fIt++ );
9792               }
9793               else
9794                 fIt = freeFaceList.erase( fIt++ );
9795             }
9796           }
9797         } // choose one of several free faces of a volume
9798
9799         if ( freeFaceList.size() == 1 ) {
9800           const SMDS_MeshElement* aFreeFace = freeFaceList.front();
9801           faceSet->insert( aFreeFace );
9802           // complete a node set with nodes of a found free face
9803           //           for ( iNode = 0; iNode < ; iNode++ )
9804           //             nodeSet->insert( fNodes[ iNode ] );
9805         }
9806
9807       } // loop on volumes of a side
9808
9809       //       // complete a set of faces if new nodes in a nodeSet appeared
9810       //       // ----------------------------------------------------------
9811       //       if ( nodeSetSize != nodeSet->size() ) {
9812       //         for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9813       //           SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9814       //           while ( fIt->more() ) { // loop on faces sharing a node
9815       //             const SMDS_MeshElement* f = fIt->next();
9816       //             if ( faceSet->find( f ) == faceSet->end() ) {
9817       //               // check if all nodes are in nodeSet and
9818       //               // complete setOfFaceNodeSet if they are
9819       //               set <const SMDS_MeshNode*> faceNodeSet;
9820       //               SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9821       //               bool allInSet = true;
9822       //               while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9823       //                 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9824       //                 if ( nodeSet->find( n ) == nodeSet->end() )
9825       //                   allInSet = false;
9826       //                 else
9827       //                   faceNodeSet.insert( n );
9828       //               }
9829       //               if ( allInSet ) {
9830       //                 faceSet->insert( f );
9831       //                 setOfFaceNodeSet.insert( faceNodeSet );
9832       //               }
9833       //             }
9834       //           }
9835       //         }
9836       //       }
9837     } // Create temporary faces, if there are volumes given
9838   } // loop on sides
9839
9840   if ( faceSet1.size() != faceSet2.size() ) {
9841     // delete temporary faces: they are in reverseElements of actual nodes
9842 //    SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
9843 //    while ( tmpFaceIt->more() )
9844 //      aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
9845 //    list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
9846 //    for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
9847 //      aMesh->RemoveElement(*tmpFaceIt);
9848     MESSAGE("Diff nb of faces");
9849     return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9850   }
9851
9852   // ============================================================
9853   // 2. Find nodes to merge:
9854   //              bind a node to remove to a node to put instead
9855   // ============================================================
9856
9857   TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
9858   if ( theFirstNode1 != theFirstNode2 )
9859     nReplaceMap.insert( TNodeNodeMap::value_type( theFirstNode1, theFirstNode2 ));
9860   if ( theSecondNode1 != theSecondNode2 )
9861     nReplaceMap.insert( TNodeNodeMap::value_type( theSecondNode1, theSecondNode2 ));
9862
9863   LinkID_Gen aLinkID_Gen( GetMeshDS() );
9864   set< long > linkIdSet; // links to process
9865   linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
9866
9867   typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
9868   list< NLink > linkList[2];
9869   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
9870   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
9871   // loop on links in linkList; find faces by links and append links
9872   // of the found faces to linkList
9873   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
9874   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
9875     NLink link[] = { *linkIt[0], *linkIt[1] };
9876     long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
9877     if ( linkIdSet.find( linkID ) == linkIdSet.end() )
9878       continue;
9879
9880     // by links, find faces in the face sets,
9881     // and find indices of link nodes in the found faces;
9882     // in a face set, there is only one or no face sharing a link
9883     // ---------------------------------------------------------------
9884
9885     const SMDS_MeshElement* face[] = { 0, 0 };
9886     //const SMDS_MeshNode* faceNodes[ 2 ][ 5 ];
9887     vector<const SMDS_MeshNode*> fnodes1(9);
9888     vector<const SMDS_MeshNode*> fnodes2(9);
9889     //const SMDS_MeshNode* notLinkNodes[ 2 ][ 2 ] = {{ 0, 0 },{ 0, 0 }} ;
9890     vector<const SMDS_MeshNode*> notLinkNodes1(6);
9891     vector<const SMDS_MeshNode*> notLinkNodes2(6);
9892     int iLinkNode[2][2];
9893     for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9894       const SMDS_MeshNode* n1 = link[iSide].first;
9895       const SMDS_MeshNode* n2 = link[iSide].second;
9896       set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9897       set< const SMDS_MeshElement* > fMap;
9898       for ( int i = 0; i < 2; i++ ) { // loop on 2 nodes of a link
9899         const SMDS_MeshNode* n = i ? n1 : n2; // a node of a link
9900         SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
9901         while ( fIt->more() ) { // loop on faces sharing a node
9902           const SMDS_MeshElement* f = fIt->next();
9903           if (faceSet->find( f ) != faceSet->end() && // f is in face set
9904               ! fMap.insert( f ).second ) // f encounters twice
9905           {
9906             if ( face[ iSide ] ) {
9907               MESSAGE( "2 faces per link " );
9908               aResult = iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES;
9909               break;
9910             }
9911             face[ iSide ] = f;
9912             faceSet->erase( f );
9913             // get face nodes and find ones of a link
9914             iNode = 0;
9915             int nbl = -1;
9916             if(f->IsPoly()) {
9917               if(iSide==0) {
9918                 fnodes1.resize(f->NbNodes()+1);
9919                 notLinkNodes1.resize(f->NbNodes()-2);
9920               }
9921               else {
9922                 fnodes2.resize(f->NbNodes()+1);
9923                 notLinkNodes2.resize(f->NbNodes()-2);
9924               }
9925             }
9926             if(!f->IsQuadratic()) {
9927               SMDS_ElemIteratorPtr nIt = f->nodesIterator();
9928               while ( nIt->more() ) {
9929                 const SMDS_MeshNode* n =
9930                   static_cast<const SMDS_MeshNode*>( nIt->next() );
9931                 if ( n == n1 ) {
9932                   iLinkNode[ iSide ][ 0 ] = iNode;
9933                 }
9934                 else if ( n == n2 ) {
9935                   iLinkNode[ iSide ][ 1 ] = iNode;
9936                 }
9937                 //else if ( notLinkNodes[ iSide ][ 0 ] )
9938                 //  notLinkNodes[ iSide ][ 1 ] = n;
9939                 //else
9940                 //  notLinkNodes[ iSide ][ 0 ] = n;
9941                 else {
9942                   nbl++;
9943                   if(iSide==0)
9944                     notLinkNodes1[nbl] = n;
9945                   //notLinkNodes1.push_back(n);
9946                   else
9947                     notLinkNodes2[nbl] = n;
9948                   //notLinkNodes2.push_back(n);
9949                 }
9950                 //faceNodes[ iSide ][ iNode++ ] = n;
9951                 if(iSide==0) {
9952                   fnodes1[iNode++] = n;
9953                 }
9954                 else {
9955                   fnodes2[iNode++] = n;
9956                 }
9957               }
9958             }
9959             else { // f->IsQuadratic()
9960               const SMDS_VtkFace* F =
9961                 dynamic_cast<const SMDS_VtkFace*>(f);
9962               if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
9963               // use special nodes iterator
9964               SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
9965               while ( anIter->more() ) {
9966                 const SMDS_MeshNode* n =
9967                   static_cast<const SMDS_MeshNode*>( anIter->next() );
9968                 if ( n == n1 ) {
9969                   iLinkNode[ iSide ][ 0 ] = iNode;
9970                 }
9971                 else if ( n == n2 ) {
9972                   iLinkNode[ iSide ][ 1 ] = iNode;
9973                 }
9974                 else {
9975                   nbl++;
9976                   if(iSide==0) {
9977                     notLinkNodes1[nbl] = n;
9978                   }
9979                   else {
9980                     notLinkNodes2[nbl] = n;
9981                   }
9982                 }
9983                 if(iSide==0) {
9984                   fnodes1[iNode++] = n;
9985                 }
9986                 else {
9987                   fnodes2[iNode++] = n;
9988                 }
9989               }
9990             }
9991             //faceNodes[ iSide ][ iNode ] = faceNodes[ iSide ][ 0 ];
9992             if(iSide==0) {
9993               fnodes1[iNode] = fnodes1[0];
9994             }
9995             else {
9996               fnodes2[iNode] = fnodes1[0];
9997             }
9998           }
9999         }
10000       }
10001     }
10002
10003     // check similarity of elements of the sides
10004     if (aResult == SEW_OK && (( face[0] && !face[1] ) || ( !face[0] && face[1] ))) {
10005       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
10006       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
10007         aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10008       }
10009       else {
10010         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10011       }
10012       break; // do not return because it s necessary to remove tmp faces
10013     }
10014
10015     // set nodes to merge
10016     // -------------------
10017
10018     if ( face[0] && face[1] )  {
10019       int nbNodes = face[0]->NbNodes();
10020       if ( nbNodes != face[1]->NbNodes() ) {
10021         MESSAGE("Diff nb of face nodes");
10022         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10023         break; // do not return because it s necessary to remove tmp faces
10024       }
10025       bool reverse[] = { false, false }; // order of notLinkNodes of quadrangle
10026       if ( nbNodes == 3 ) {
10027         //nReplaceMap.insert( TNodeNodeMap::value_type
10028         //                   ( notLinkNodes[0][0], notLinkNodes[1][0] ));
10029         nReplaceMap.insert( TNodeNodeMap::value_type
10030                             ( notLinkNodes1[0], notLinkNodes2[0] ));
10031       }
10032       else {
10033         for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
10034           // analyse link orientation in faces
10035           int i1 = iLinkNode[ iSide ][ 0 ];
10036           int i2 = iLinkNode[ iSide ][ 1 ];
10037           reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
10038           // if notLinkNodes are the first and the last ones, then
10039           // their order does not correspond to the link orientation
10040           if (( i1 == 1 && i2 == 2 ) ||
10041               ( i1 == 2 && i2 == 1 ))
10042             reverse[ iSide ] = !reverse[ iSide ];
10043         }
10044         if ( reverse[0] == reverse[1] ) {
10045           //nReplaceMap.insert( TNodeNodeMap::value_type
10046           //                   ( notLinkNodes[0][0], notLinkNodes[1][0] ));
10047           //nReplaceMap.insert( TNodeNodeMap::value_type
10048           //                   ( notLinkNodes[0][1], notLinkNodes[1][1] ));
10049           for(int nn=0; nn<nbNodes-2; nn++) {
10050             nReplaceMap.insert( TNodeNodeMap::value_type
10051                                 ( notLinkNodes1[nn], notLinkNodes2[nn] ));
10052           }
10053         }
10054         else {
10055           //nReplaceMap.insert( TNodeNodeMap::value_type
10056           //                   ( notLinkNodes[0][0], notLinkNodes[1][1] ));
10057           //nReplaceMap.insert( TNodeNodeMap::value_type
10058           //                   ( notLinkNodes[0][1], notLinkNodes[1][0] ));
10059           for(int nn=0; nn<nbNodes-2; nn++) {
10060             nReplaceMap.insert( TNodeNodeMap::value_type
10061                                 ( notLinkNodes1[nn], notLinkNodes2[nbNodes-3-nn] ));
10062           }
10063         }
10064       }
10065
10066       // add other links of the faces to linkList
10067       // -----------------------------------------
10068
10069       //const SMDS_MeshNode** nodes = faceNodes[ 0 ];
10070       for ( iNode = 0; iNode < nbNodes; iNode++ )  {
10071         //linkID = aLinkID_Gen.GetLinkID( nodes[iNode], nodes[iNode+1] );
10072         linkID = aLinkID_Gen.GetLinkID( fnodes1[iNode], fnodes1[iNode+1] );
10073         pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
10074         if ( !iter_isnew.second ) { // already in a set: no need to process
10075           linkIdSet.erase( iter_isnew.first );
10076         }
10077         else // new in set == encountered for the first time: add
10078         {
10079           //const SMDS_MeshNode* n1 = nodes[ iNode ];
10080           //const SMDS_MeshNode* n2 = nodes[ iNode + 1];
10081           const SMDS_MeshNode* n1 = fnodes1[ iNode ];
10082           const SMDS_MeshNode* n2 = fnodes1[ iNode + 1];
10083           linkList[0].push_back ( NLink( n1, n2 ));
10084           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
10085         }
10086       }
10087     } // 2 faces found
10088   } // loop on link lists
10089
10090   if ( aResult == SEW_OK &&
10091        ( linkIt[0] != linkList[0].end() ||
10092          !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
10093     MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
10094              " " << (faceSetPtr[1]->empty()));
10095     aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10096   }
10097
10098   // ====================================================================
10099   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
10100   // ====================================================================
10101
10102   // delete temporary faces: they are in reverseElements of actual nodes
10103 //  SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
10104 //  while ( tmpFaceIt->more() )
10105 //    aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
10106 //  list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
10107 //  for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
10108 //    aMesh->RemoveElement(*tmpFaceIt);
10109
10110   if ( aResult != SEW_OK)
10111     return aResult;
10112
10113   list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
10114   // loop on nodes replacement map
10115   TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
10116   for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
10117     if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
10118       const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
10119       nodeIDsToRemove.push_back( nToRemove->GetID() );
10120       // loop on elements sharing nToRemove
10121       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
10122       while ( invElemIt->more() ) {
10123         const SMDS_MeshElement* e = invElemIt->next();
10124         // get a new suite of nodes: make replacement
10125         int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
10126         vector< const SMDS_MeshNode*> nodes( nbNodes );
10127         SMDS_ElemIteratorPtr nIt = e->nodesIterator();
10128         while ( nIt->more() ) {
10129           const SMDS_MeshNode* n =
10130             static_cast<const SMDS_MeshNode*>( nIt->next() );
10131           nnIt = nReplaceMap.find( n );
10132           if ( nnIt != nReplaceMap.end() ) {
10133             nbReplaced++;
10134             n = (*nnIt).second;
10135           }
10136           nodes[ i++ ] = n;
10137         }
10138         //       if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
10139         //         elemIDsToRemove.push_back( e->GetID() );
10140         //       else
10141         if ( nbReplaced )
10142           {
10143             SMDSAbs_ElementType etyp = e->GetType();
10144             SMDS_MeshElement* newElem = this->AddElement(nodes, etyp, false);
10145             if (newElem)
10146               {
10147                 myLastCreatedElems.Append(newElem);
10148                 AddToSameGroups(newElem, e, aMesh);
10149                 int aShapeId = e->getshapeId();
10150                 if ( aShapeId )
10151                   {
10152                     aMesh->SetMeshElementOnShape( newElem, aShapeId );
10153                   }
10154               }
10155             aMesh->RemoveElement(e);
10156           }
10157       }
10158     }
10159
10160   Remove( nodeIDsToRemove, true );
10161
10162   return aResult;
10163 }
10164
10165 //================================================================================
10166 /*!
10167  * \brief Find corresponding nodes in two sets of faces
10168  * \param theSide1 - first face set
10169  * \param theSide2 - second first face
10170  * \param theFirstNode1 - a boundary node of set 1
10171  * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
10172  * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
10173  * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
10174  * \param nReplaceMap - output map of corresponding nodes
10175  * \return bool  - is a success or not
10176  */
10177 //================================================================================
10178
10179 #ifdef _DEBUG_
10180 //#define DEBUG_MATCHING_NODES
10181 #endif
10182
10183 SMESH_MeshEditor::Sew_Error
10184 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
10185                                     set<const SMDS_MeshElement*>& theSide2,
10186                                     const SMDS_MeshNode*          theFirstNode1,
10187                                     const SMDS_MeshNode*          theFirstNode2,
10188                                     const SMDS_MeshNode*          theSecondNode1,
10189                                     const SMDS_MeshNode*          theSecondNode2,
10190                                     TNodeNodeMap &                nReplaceMap)
10191 {
10192   set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
10193
10194   nReplaceMap.clear();
10195   if ( theFirstNode1 != theFirstNode2 )
10196     nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
10197   if ( theSecondNode1 != theSecondNode2 )
10198     nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
10199
10200   set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
10201   linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
10202
10203   list< NLink > linkList[2];
10204   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
10205   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
10206
10207   // loop on links in linkList; find faces by links and append links
10208   // of the found faces to linkList
10209   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
10210   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
10211     NLink link[] = { *linkIt[0], *linkIt[1] };
10212     if ( linkSet.find( link[0] ) == linkSet.end() )
10213       continue;
10214
10215     // by links, find faces in the face sets,
10216     // and find indices of link nodes in the found faces;
10217     // in a face set, there is only one or no face sharing a link
10218     // ---------------------------------------------------------------
10219
10220     const SMDS_MeshElement* face[] = { 0, 0 };
10221     list<const SMDS_MeshNode*> notLinkNodes[2];
10222     //bool reverse[] = { false, false }; // order of notLinkNodes
10223     int nbNodes[2];
10224     for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
10225     {
10226       const SMDS_MeshNode* n1 = link[iSide].first;
10227       const SMDS_MeshNode* n2 = link[iSide].second;
10228       set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
10229       set< const SMDS_MeshElement* > facesOfNode1;
10230       for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
10231       {
10232         // during a loop of the first node, we find all faces around n1,
10233         // during a loop of the second node, we find one face sharing both n1 and n2
10234         const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
10235         SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
10236         while ( fIt->more() ) { // loop on faces sharing a node
10237           const SMDS_MeshElement* f = fIt->next();
10238           if (faceSet->find( f ) != faceSet->end() && // f is in face set
10239               ! facesOfNode1.insert( f ).second ) // f encounters twice
10240           {
10241             if ( face[ iSide ] ) {
10242               MESSAGE( "2 faces per link " );
10243               return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10244             }
10245             face[ iSide ] = f;
10246             faceSet->erase( f );
10247
10248             // get not link nodes
10249             int nbN = f->NbNodes();
10250             if ( f->IsQuadratic() )
10251               nbN /= 2;
10252             nbNodes[ iSide ] = nbN;
10253             list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
10254             int i1 = f->GetNodeIndex( n1 );
10255             int i2 = f->GetNodeIndex( n2 );
10256             int iEnd = nbN, iBeg = -1, iDelta = 1;
10257             bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
10258             if ( reverse ) {
10259               std::swap( iEnd, iBeg ); iDelta = -1;
10260             }
10261             int i = i2;
10262             while ( true ) {
10263               i += iDelta;
10264               if ( i == iEnd ) i = iBeg + iDelta;
10265               if ( i == i1 ) break;
10266               nodes.push_back ( f->GetNode( i ) );
10267             }
10268           }
10269         }
10270       }
10271     }
10272     // check similarity of elements of the sides
10273     if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
10274       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
10275       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
10276         return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10277       }
10278       else {
10279         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10280       }
10281     }
10282
10283     // set nodes to merge
10284     // -------------------
10285
10286     if ( face[0] && face[1] )  {
10287       if ( nbNodes[0] != nbNodes[1] ) {
10288         MESSAGE("Diff nb of face nodes");
10289         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10290       }
10291 #ifdef DEBUG_MATCHING_NODES
10292       MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
10293                 << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
10294                 << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
10295 #endif
10296       int nbN = nbNodes[0];
10297       {
10298         list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
10299         list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
10300         for ( int i = 0 ; i < nbN - 2; ++i ) {
10301 #ifdef DEBUG_MATCHING_NODES
10302           MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
10303 #endif
10304           nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
10305         }
10306       }
10307
10308       // add other links of the face 1 to linkList
10309       // -----------------------------------------
10310
10311       const SMDS_MeshElement* f0 = face[0];
10312       const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
10313       for ( int i = 0; i < nbN; i++ )
10314       {
10315         const SMDS_MeshNode* n2 = f0->GetNode( i );
10316         pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
10317           linkSet.insert( SMESH_TLink( n1, n2 ));
10318         if ( !iter_isnew.second ) { // already in a set: no need to process
10319           linkSet.erase( iter_isnew.first );
10320         }
10321         else // new in set == encountered for the first time: add
10322         {
10323 #ifdef DEBUG_MATCHING_NODES
10324           MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
10325                     << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
10326 #endif
10327           linkList[0].push_back ( NLink( n1, n2 ));
10328           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
10329         }
10330         n1 = n2;
10331       }
10332     } // 2 faces found
10333   } // loop on link lists
10334
10335   return SEW_OK;
10336 }
10337
10338 //================================================================================
10339 /*!
10340   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10341   \param theElems - the list of elements (edges or faces) to be replicated
10342   The nodes for duplication could be found from these elements
10343   \param theNodesNot - list of nodes to NOT replicate
10344   \param theAffectedElems - the list of elements (cells and edges) to which the 
10345   replicated nodes should be associated to.
10346   \return TRUE if operation has been completed successfully, FALSE otherwise
10347 */
10348 //================================================================================
10349
10350 bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
10351                                     const TIDSortedElemSet& theNodesNot,
10352                                     const TIDSortedElemSet& theAffectedElems )
10353 {
10354   myLastCreatedElems.Clear();
10355   myLastCreatedNodes.Clear();
10356
10357   if ( theElems.size() == 0 )
10358     return false;
10359
10360   SMESHDS_Mesh* aMeshDS = GetMeshDS();
10361   if ( !aMeshDS )
10362     return false;
10363
10364   bool res = false;
10365   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10366   // duplicate elements and nodes
10367   res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true );
10368   // replce nodes by duplications
10369   res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false );
10370   return res;
10371 }
10372
10373 //================================================================================
10374 /*!
10375   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10376   \param theMeshDS - mesh instance
10377   \param theElems - the elements replicated or modified (nodes should be changed)
10378   \param theNodesNot - nodes to NOT replicate
10379   \param theNodeNodeMap - relation of old node to new created node
10380   \param theIsDoubleElem - flag os to replicate element or modify
10381   \return TRUE if operation has been completed successfully, FALSE otherwise
10382 */
10383 //================================================================================
10384
10385 bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh*     theMeshDS,
10386                                     const TIDSortedElemSet& theElems,
10387                                     const TIDSortedElemSet& theNodesNot,
10388                                     std::map< const SMDS_MeshNode*,
10389                                     const SMDS_MeshNode* >& theNodeNodeMap,
10390                                     const bool theIsDoubleElem )
10391 {
10392   MESSAGE("doubleNodes");
10393   // iterate on through element and duplicate them (by nodes duplication)
10394   bool res = false;
10395   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10396   for ( ;  elemItr != theElems.end(); ++elemItr )
10397   {
10398     const SMDS_MeshElement* anElem = *elemItr;
10399     if (!anElem)
10400       continue;
10401
10402     bool isDuplicate = false;
10403     // duplicate nodes to duplicate element
10404     std::vector<const SMDS_MeshNode*> newNodes( anElem->NbNodes() );
10405     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10406     int ind = 0;
10407     while ( anIter->more() ) 
10408     { 
10409
10410       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10411       SMDS_MeshNode* aNewNode = aCurrNode;
10412       if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() )
10413         aNewNode = (SMDS_MeshNode*)theNodeNodeMap[ aCurrNode ];
10414       else if ( theIsDoubleElem && theNodesNot.find( aCurrNode ) == theNodesNot.end() )
10415       {
10416         // duplicate node
10417         aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
10418         theNodeNodeMap[ aCurrNode ] = aNewNode;
10419         myLastCreatedNodes.Append( aNewNode );
10420       }
10421       isDuplicate |= (aCurrNode != aNewNode);
10422       newNodes[ ind++ ] = aNewNode;
10423     }
10424     if ( !isDuplicate )
10425       continue;
10426
10427     if ( theIsDoubleElem )
10428       AddElement(newNodes, anElem->GetType(), anElem->IsPoly());
10429     else
10430       {
10431       MESSAGE("ChangeElementNodes");
10432       theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
10433       }
10434     res = true;
10435   }
10436   return res;
10437 }
10438
10439 //================================================================================
10440 /*!
10441   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10442   \param theNodes - identifiers of nodes to be doubled
10443   \param theModifiedElems - identifiers of elements to be updated by the new (doubled) 
10444          nodes. If list of element identifiers is empty then nodes are doubled but 
10445          they not assigned to elements
10446   \return TRUE if operation has been completed successfully, FALSE otherwise
10447 */
10448 //================================================================================
10449
10450 bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes, 
10451                                     const std::list< int >& theListOfModifiedElems )
10452 {
10453   MESSAGE("DoubleNodes");
10454   myLastCreatedElems.Clear();
10455   myLastCreatedNodes.Clear();
10456
10457   if ( theListOfNodes.size() == 0 )
10458     return false;
10459
10460   SMESHDS_Mesh* aMeshDS = GetMeshDS();
10461   if ( !aMeshDS )
10462     return false;
10463
10464   // iterate through nodes and duplicate them
10465
10466   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10467
10468   std::list< int >::const_iterator aNodeIter;
10469   for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
10470   {
10471     int aCurr = *aNodeIter;
10472     SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
10473     if ( !aNode )
10474       continue;
10475
10476     // duplicate node
10477
10478     const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
10479     if ( aNewNode )
10480     {
10481       anOldNodeToNewNode[ aNode ] = aNewNode;
10482       myLastCreatedNodes.Append( aNewNode );
10483     }
10484   }
10485
10486   // Create map of new nodes for modified elements
10487
10488   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
10489
10490   std::list< int >::const_iterator anElemIter;
10491   for ( anElemIter = theListOfModifiedElems.begin(); 
10492         anElemIter != theListOfModifiedElems.end(); ++anElemIter )
10493   {
10494     int aCurr = *anElemIter;
10495     SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
10496     if ( !anElem )
10497       continue;
10498
10499     vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
10500
10501     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10502     int ind = 0;
10503     while ( anIter->more() ) 
10504     { 
10505       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10506       if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
10507       {
10508         const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
10509         aNodeArr[ ind++ ] = aNewNode;
10510       }
10511       else
10512         aNodeArr[ ind++ ] = aCurrNode;
10513     }
10514     anElemToNodes[ anElem ] = aNodeArr;
10515   }
10516
10517   // Change nodes of elements  
10518
10519   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
10520     anElemToNodesIter = anElemToNodes.begin();
10521   for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
10522   {
10523     const SMDS_MeshElement* anElem = anElemToNodesIter->first;
10524     vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
10525     if ( anElem )
10526       {
10527       MESSAGE("ChangeElementNodes");
10528       aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
10529       }
10530   }
10531
10532   return true;
10533 }
10534
10535 namespace {
10536
10537   //================================================================================
10538   /*!
10539   \brief Check if element located inside shape
10540   \return TRUE if IN or ON shape, FALSE otherwise
10541   */
10542   //================================================================================
10543
10544   template<class Classifier>
10545   bool isInside(const SMDS_MeshElement* theElem,
10546                 Classifier&             theClassifier,
10547                 const double            theTol)
10548   {
10549     gp_XYZ centerXYZ (0, 0, 0);
10550     SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
10551     while (aNodeItr->more())
10552       centerXYZ += SMESH_TNodeXYZ(cast2Node( aNodeItr->next()));
10553
10554     gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
10555     theClassifier.Perform(aPnt, theTol);
10556     TopAbs_State aState = theClassifier.State();
10557     return (aState == TopAbs_IN || aState == TopAbs_ON );
10558   }
10559
10560   //================================================================================
10561   /*!
10562    * \brief Classifier of the 3D point on the TopoDS_Face
10563    *        with interaface suitable for isInside()
10564    */
10565   //================================================================================
10566
10567   struct _FaceClassifier
10568   {
10569     Extrema_ExtPS       _extremum;
10570     BRepAdaptor_Surface _surface;
10571     TopAbs_State        _state;
10572
10573     _FaceClassifier(const TopoDS_Face& face):_extremum(),_surface(face),_state(TopAbs_OUT)
10574     {
10575       _extremum.Initialize( _surface,
10576                             _surface.FirstUParameter(), _surface.LastUParameter(),
10577                             _surface.FirstVParameter(), _surface.LastVParameter(),
10578                             _surface.Tolerance(), _surface.Tolerance() );
10579     }
10580     void Perform(const gp_Pnt& aPnt, double theTol)
10581     {
10582       _state = TopAbs_OUT;
10583       _extremum.Perform(aPnt);
10584       if ( _extremum.IsDone() )
10585         for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol)
10586 #if OCC_VERSION_LARGE > 0x06040000 // Porting to OCCT6.5.1
10587           _state = ( _extremum.SquareDistance(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
10588 #else
10589           _state = ( _extremum.Value(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
10590 #endif
10591     }
10592     TopAbs_State State() const
10593     {
10594       return _state;
10595     }
10596   };
10597 }
10598
10599 //================================================================================
10600 /*!
10601   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10602   \param theElems - group of of elements (edges or faces) to be replicated
10603   \param theNodesNot - group of nodes not to replicate
10604   \param theShape - shape to detect affected elements (element which geometric center
10605   located on or inside shape).
10606   The replicated nodes should be associated to affected elements.
10607   \return TRUE if operation has been completed successfully, FALSE otherwise
10608 */
10609 //================================================================================
10610
10611 bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
10612                                             const TIDSortedElemSet& theNodesNot,
10613                                             const TopoDS_Shape&     theShape )
10614 {
10615   if ( theShape.IsNull() )
10616     return false;
10617
10618   const double aTol = Precision::Confusion();
10619   auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
10620   auto_ptr<_FaceClassifier>              aFaceClassifier;
10621   if ( theShape.ShapeType() == TopAbs_SOLID )
10622   {
10623     bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
10624     bsc3d->PerformInfinitePoint(aTol);
10625   }
10626   else if (theShape.ShapeType() == TopAbs_FACE )
10627   {
10628     aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
10629   }
10630
10631   // iterates on indicated elements and get elements by back references from their nodes
10632   TIDSortedElemSet anAffected;
10633   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10634   for ( ;  elemItr != theElems.end(); ++elemItr )
10635   {
10636     SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
10637     if (!anElem)
10638       continue;
10639
10640     SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
10641     while ( nodeItr->more() )
10642     {
10643       const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
10644       if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
10645         continue;
10646       SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
10647       while ( backElemItr->more() )
10648       {
10649         const SMDS_MeshElement* curElem = backElemItr->next();
10650         if ( curElem && theElems.find(curElem) == theElems.end() &&
10651              ( bsc3d.get() ?
10652                isInside( curElem, *bsc3d, aTol ) :
10653                isInside( curElem, *aFaceClassifier, aTol )))
10654           anAffected.insert( curElem );
10655       }
10656     }
10657   }
10658   return DoubleNodes( theElems, theNodesNot, anAffected );
10659 }
10660
10661 /*!
10662  *  \brief compute an oriented angle between two planes defined by four points.
10663  *  The vector (p0,p1) defines the intersection of the 2 planes (p0,p1,g1) and (p0,p1,g2)
10664  *  @param p0 base of the rotation axe
10665  *  @param p1 extremity of the rotation axe
10666  *  @param g1 belongs to the first plane
10667  *  @param g2 belongs to the second plane
10668  */
10669 double SMESH_MeshEditor::OrientedAngle(const gp_Pnt& p0, const gp_Pnt& p1, const gp_Pnt& g1, const gp_Pnt& g2)
10670 {
10671 //  MESSAGE("    p0: " << p0.X() << " " << p0.Y() << " " << p0.Z());
10672 //  MESSAGE("    p1: " << p1.X() << " " << p1.Y() << " " << p1.Z());
10673 //  MESSAGE("    g1: " << g1.X() << " " << g1.Y() << " " << g1.Z());
10674 //  MESSAGE("    g2: " << g2.X() << " " << g2.Y() << " " << g2.Z());
10675   gp_Vec vref(p0, p1);
10676   gp_Vec v1(p0, g1);
10677   gp_Vec v2(p0, g2);
10678   gp_Vec n1 = vref.Crossed(v1);
10679   gp_Vec n2 = vref.Crossed(v2);
10680   return n2.AngleWithRef(n1, vref);
10681 }
10682
10683 /*!
10684  * \brief Double nodes on shared faces between groups of volumes and create flat elements on demand.
10685  * The list of groups must describe a partition of the mesh volumes.
10686  * The nodes of the internal faces at the boundaries of the groups are doubled.
10687  * In option, the internal faces are replaced by flat elements.
10688  * Triangles are transformed in prisms, and quadrangles in hexahedrons.
10689  * The flat elements are stored in groups of volumes.
10690  * @param theElems - list of groups of volumes, where a group of volume is a set of
10691  * SMDS_MeshElements sorted by Id.
10692  * @param createJointElems - if TRUE, create the elements
10693  * @return TRUE if operation has been completed successfully, FALSE otherwise
10694  */
10695 bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSortedElemSet>& theElems,
10696                                                      bool createJointElems)
10697 {
10698   MESSAGE("----------------------------------------------");
10699   MESSAGE("SMESH_MeshEditor::doubleNodesOnGroupBoundaries");
10700   MESSAGE("----------------------------------------------");
10701
10702   SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
10703   meshDS->BuildDownWardConnectivity(true);
10704   CHRONO(50);
10705   SMDS_UnstructuredGrid *grid = meshDS->getGrid();
10706
10707   // --- build the list of faces shared by 2 domains (group of elements), with their domain and volume indexes
10708   //     build the list of cells with only a node or an edge on the border, with their domain and volume indexes
10709   //     build the list of nodes shared by 2 or more domains, with their domain indexes
10710
10711   std::map<DownIdType, std::map<int,int>, DownIdCompare> faceDomains; // face --> (id domain --> id volume)
10712   std::map<int,int>celldom; // cell vtkId --> domain
10713   std::map<DownIdType, std::map<int,int>, DownIdCompare> cellDomains;  // oldNode --> (id domain --> id cell)
10714   std::map<int, std::map<int,int> > nodeDomains; // oldId -->  (domainId --> newId)
10715   faceDomains.clear();
10716   celldom.clear();
10717   cellDomains.clear();
10718   nodeDomains.clear();
10719   std::map<int,int> emptyMap;
10720   std::set<int> emptySet;
10721   emptyMap.clear();
10722
10723   for (int idom = 0; idom < theElems.size(); idom++)
10724     {
10725
10726       // --- build a map (face to duplicate --> volume to modify)
10727       //     with all the faces shared by 2 domains (group of elements)
10728       //     and corresponding volume of this domain, for each shared face.
10729       //     a volume has a face shared by 2 domains if it has a neighbor which is not in is domain.
10730
10731       //MESSAGE("Domain " << idom);
10732       const TIDSortedElemSet& domain = theElems[idom];
10733       TIDSortedElemSet::const_iterator elemItr = domain.begin();
10734       for (; elemItr != domain.end(); ++elemItr)
10735         {
10736           SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
10737           if (!anElem)
10738             continue;
10739           int vtkId = anElem->getVtkId();
10740           //MESSAGE("  vtkId " << vtkId << " smdsId " << anElem->GetID());
10741           int neighborsVtkIds[NBMAXNEIGHBORS];
10742           int downIds[NBMAXNEIGHBORS];
10743           unsigned char downTypes[NBMAXNEIGHBORS];
10744           int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
10745           for (int n = 0; n < nbNeighbors; n++)
10746             {
10747               int smdsId = meshDS->fromVtkToSmds(neighborsVtkIds[n]);
10748               const SMDS_MeshElement* elem = meshDS->FindElement(smdsId);
10749               if (! domain.count(elem)) // neighbor is in another domain : face is shared
10750                 {
10751                   DownIdType face(downIds[n], downTypes[n]);
10752                   if (!faceDomains.count(face))
10753                     faceDomains[face] = emptyMap; // create an empty entry for face
10754                   if (!faceDomains[face].count(idom))
10755                     {
10756                       faceDomains[face][idom] = vtkId; // volume associated to face in this domain
10757                       celldom[vtkId] = idom;
10758                       //MESSAGE("       cell with a border " << vtkId << " domain " << idom);
10759                     }
10760                 }
10761             }
10762         }
10763     }
10764
10765   //MESSAGE("Number of shared faces " << faceDomains.size());
10766   std::map<DownIdType, std::map<int, int>, DownIdCompare>::iterator itface;
10767
10768   // --- explore the shared faces domain by domain,
10769   //     explore the nodes of the face and see if they belong to a cell in the domain,
10770   //     which has only a node or an edge on the border (not a shared face)
10771
10772   for (int idomain = 0; idomain < theElems.size(); idomain++)
10773     {
10774       //MESSAGE("Domain " << idomain);
10775       const TIDSortedElemSet& domain = theElems[idomain];
10776       itface = faceDomains.begin();
10777       for (; itface != faceDomains.end(); ++itface)
10778         {
10779           std::map<int, int> domvol = itface->second;
10780           if (!domvol.count(idomain))
10781             continue;
10782           DownIdType face = itface->first;
10783           //MESSAGE(" --- face " << face.cellId);
10784           std::set<int> oldNodes;
10785           oldNodes.clear();
10786           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10787           std::set<int>::iterator itn = oldNodes.begin();
10788           for (; itn != oldNodes.end(); ++itn)
10789             {
10790               int oldId = *itn;
10791               //MESSAGE("     node " << oldId);
10792               std::set<int> cells;
10793               cells.clear();
10794               vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId);
10795               for (int i=0; i<l.ncells; i++)
10796                 {
10797                   int vtkId = l.cells[i];
10798                   const SMDS_MeshElement* anElem = GetMeshDS()->FindElement(GetMeshDS()->fromVtkToSmds(vtkId));
10799                   if (!domain.count(anElem))
10800                     continue;
10801                   int vtkType = grid->GetCellType(vtkId);
10802                   int downId = grid->CellIdToDownId(vtkId);
10803                   if (downId < 0)
10804                     {
10805                       MESSAGE("doubleNodesOnGroupBoundaries: internal algorithm problem");
10806                       continue; // not OK at this stage of the algorithm:
10807                                 //no cells created after BuildDownWardConnectivity
10808                     }
10809                   DownIdType aCell(downId, vtkType);
10810                   if (celldom.count(vtkId))
10811                     continue;
10812                   cellDomains[aCell][idomain] = vtkId;
10813                   celldom[vtkId] = idomain;
10814                   //MESSAGE("       cell " << vtkId << " domain " << idomain);
10815                 }
10816             }
10817         }
10818     }
10819
10820   // --- explore the shared faces domain by domain, to duplicate the nodes in a coherent way
10821   //     for each shared face, get the nodes
10822   //     for each node, for each domain of the face, create a clone of the node
10823
10824   // --- edges at the intersection of 3 or 4 domains, with the order of domains to build
10825   //     junction elements of type prism or hexa. the key is the pair of nodesId (lower first)
10826   //     the value is the ordered domain ids. (more than 4 domains not taken into account)
10827
10828   std::map<std::vector<int>, std::vector<int> > edgesMultiDomains; // nodes of edge --> ordered domains
10829   std::map<int, std::vector<int> > mutipleNodes; // nodes multi domains with domain order
10830   std::map<int, std::vector<int> > mutipleNodesToFace; // nodes multi domains with domain order to transform in Face (junction between 3 or more 2D domains)
10831
10832   for (int idomain = 0; idomain < theElems.size(); idomain++)
10833     {
10834       itface = faceDomains.begin();
10835       for (; itface != faceDomains.end(); ++itface)
10836         {
10837           std::map<int, int> domvol = itface->second;
10838           if (!domvol.count(idomain))
10839             continue;
10840           DownIdType face = itface->first;
10841           //MESSAGE(" --- face " << face.cellId);
10842           std::set<int> oldNodes;
10843           oldNodes.clear();
10844           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10845           bool isMultipleDetected = false;
10846           std::set<int>::iterator itn = oldNodes.begin();
10847           for (; itn != oldNodes.end(); ++itn)
10848             {
10849               int oldId = *itn;
10850               //MESSAGE("     node " << oldId);
10851               if (!nodeDomains.count(oldId))
10852                 nodeDomains[oldId] = emptyMap; // create an empty entry for node
10853               if (nodeDomains[oldId].empty())
10854                 nodeDomains[oldId][idomain] = oldId; // keep the old node in the first domain
10855               std::map<int, int>::iterator itdom = domvol.begin();
10856               for (; itdom != domvol.end(); ++itdom)
10857                 {
10858                   int idom = itdom->first;
10859                   //MESSAGE("         domain " << idom);
10860                   if (!nodeDomains[oldId].count(idom)) // --- node to clone
10861                     {
10862                       if (nodeDomains[oldId].size() >= 2) // a multiple node
10863                         {
10864                           vector<int> orderedDoms;
10865                           //MESSAGE("multiple node " << oldId);
10866                           isMultipleDetected =true;
10867                           if (mutipleNodes.count(oldId))
10868                             orderedDoms = mutipleNodes[oldId];
10869                           else
10870                             {
10871                               map<int,int>::iterator it = nodeDomains[oldId].begin();
10872                               for (; it != nodeDomains[oldId].end(); ++it)
10873                                 orderedDoms.push_back(it->first);
10874                             }
10875                           orderedDoms.push_back(idom); // TODO order ==> push_front or back
10876                           //stringstream txt;
10877                           //for (int i=0; i<orderedDoms.size(); i++)
10878                           //  txt << orderedDoms[i] << " ";
10879                           //MESSAGE("orderedDoms " << txt.str());
10880                           mutipleNodes[oldId] = orderedDoms;
10881                         }
10882                       double *coords = grid->GetPoint(oldId);
10883                       SMDS_MeshNode *newNode = meshDS->AddNode(coords[0], coords[1], coords[2]);
10884                       int newId = newNode->getVtkId();
10885                       nodeDomains[oldId][idom] = newId; // cloned node for other domains
10886                       //MESSAGE("   newNode " << newId << " oldNode " << oldId << " size=" <<nodeDomains[oldId].size());
10887                     }
10888                   if (nodeDomains[oldId].size() >= 3)
10889                     {
10890                       //MESSAGE("confirm multiple node " << oldId);
10891                       isMultipleDetected =true;
10892                     }
10893                 }
10894             }
10895           if (isMultipleDetected) // check if an edge of the face is shared between 3 or more domains
10896             {
10897               //MESSAGE("multiple Nodes detected on a shared face");
10898               int downId = itface->first.cellId;
10899               unsigned char cellType = itface->first.cellType;
10900               // --- shared edge or shared face ?
10901               if ((cellType == VTK_LINE) || (cellType == VTK_QUADRATIC_EDGE)) // shared edge (between two faces)
10902                 {
10903                   int nodes[3];
10904                   int nbNodes = grid->getDownArray(cellType)->getNodes(downId, nodes);
10905                   for (int i=0; i< nbNodes; i=i+nbNodes-1) // i=0 , i=nbNodes-1
10906                     if (mutipleNodes.count(nodes[i]))
10907                       if (!mutipleNodesToFace.count(nodes[i]))
10908                         mutipleNodesToFace[nodes[i]] = mutipleNodes[nodes[i]];
10909                }
10910               else // shared face (between two volumes)
10911                 {
10912                   int nbEdges = grid->getDownArray(cellType)->getNumberOfDownCells(downId);
10913                   const int* downEdgeIds = grid->getDownArray(cellType)->getDownCells(downId);
10914                   const unsigned char* edgeType = grid->getDownArray(cellType)->getDownTypes(downId);
10915                   for (int ie =0; ie < nbEdges; ie++)
10916                     {
10917                       int nodes[3];
10918                       int nbNodes = grid->getDownArray(edgeType[ie])->getNodes(downEdgeIds[ie], nodes);
10919                       if (mutipleNodes.count(nodes[0]) && mutipleNodes.count(nodes[nbNodes-1]))
10920                         {
10921                           vector<int> vn0 = mutipleNodes[nodes[0]];
10922                           vector<int> vn1 = mutipleNodes[nodes[nbNodes - 1]];
10923                           sort( vn0.begin(), vn0.end() );
10924                           sort( vn1.begin(), vn1.end() );
10925                           if (vn0 == vn1)
10926                             {
10927                               //MESSAGE(" detect edgesMultiDomains " << nodes[0] << " " << nodes[nbNodes - 1]);
10928                               double *coords = grid->GetPoint(nodes[0]);
10929                               gp_Pnt p0(coords[0], coords[1], coords[2]);
10930                               coords = grid->GetPoint(nodes[nbNodes - 1]);
10931                               gp_Pnt p1(coords[0], coords[1], coords[2]);
10932                               gp_Pnt gref;
10933                               int vtkVolIds[1000];  // an edge can belong to a lot of volumes
10934                               map<int, SMDS_VtkVolume*> domvol; // domain --> a volume with the edge
10935                               map<int, double> angleDom; // oriented angles between planes defined by edge and volume centers
10936                               int nbvol = grid->GetParentVolumes(vtkVolIds, downEdgeIds[ie], edgeType[ie]);
10937                               for (int id=0; id < vn0.size(); id++)
10938                                 {
10939                                   int idom = vn0[id];
10940                                   for (int ivol=0; ivol<nbvol; ivol++)
10941                                     {
10942                                       int smdsId = meshDS->fromVtkToSmds(vtkVolIds[ivol]);
10943                                       SMDS_MeshElement* elem = (SMDS_MeshElement*)meshDS->FindElement(smdsId);
10944                                       if (theElems[idom].count(elem))
10945                                         {
10946                                           SMDS_VtkVolume* svol = dynamic_cast<SMDS_VtkVolume*>(elem);
10947                                           domvol[idom] = svol;
10948                                           //MESSAGE("  domain " << idom << " volume " << elem->GetID());
10949                                           double values[3];
10950                                           vtkIdType npts = 0;
10951                                           vtkIdType* pts = 0;
10952                                           grid->GetCellPoints(vtkVolIds[ivol], npts, pts);
10953                                           SMDS_VtkVolume::gravityCenter(grid, pts, npts, values);
10954                                           if (id ==0)
10955                                             {
10956                                               gref.SetXYZ(gp_XYZ(values[0], values[1], values[2]));
10957                                               angleDom[idom] = 0;
10958                                             }
10959                                           else
10960                                             {
10961                                               gp_Pnt g(values[0], values[1], values[2]);
10962                                               angleDom[idom] = OrientedAngle(p0, p1, gref, g); // -pi<angle<+pi
10963                                               //MESSAGE("  angle=" << angleDom[idom]);
10964                                             }
10965                                           break;
10966                                         }
10967                                     }
10968                                 }
10969                               map<double, int> sortedDom; // sort domains by angle
10970                               for (map<int, double>::iterator ia = angleDom.begin(); ia != angleDom.end(); ++ia)
10971                                 sortedDom[ia->second] = ia->first;
10972                               vector<int> vnodes;
10973                               vector<int> vdom;
10974                               for (map<double, int>::iterator ib = sortedDom.begin(); ib != sortedDom.end(); ++ib)
10975                                 {
10976                                   vdom.push_back(ib->second);
10977                                   //MESSAGE("  ordered domain " << ib->second << "  angle " << ib->first);
10978                                 }
10979                               for (int ino = 0; ino < nbNodes; ino++)
10980                                 vnodes.push_back(nodes[ino]);
10981                               edgesMultiDomains[vnodes] = vdom; // nodes vector --> ordered domains
10982                             }
10983                         }
10984                     }
10985                 }
10986             }
10987         }
10988     }
10989
10990   // --- iterate on shared faces (volumes to modify, face to extrude)
10991   //     get node id's of the face (id SMDS = id VTK)
10992   //     create flat element with old and new nodes if requested
10993
10994   // --- new quad nodes on flat quad elements: oldId --> ((domain1 X domain2) --> newId)
10995   //     (domain1 X domain2) = domain1 + MAXINT*domain2
10996
10997   std::map<int, std::map<long,int> > nodeQuadDomains;
10998   std::map<std::string, SMESH_Group*> mapOfJunctionGroups;
10999
11000   if (createJointElems)
11001     {
11002       itface = faceDomains.begin();
11003       for (; itface != faceDomains.end(); ++itface)
11004         {
11005           DownIdType face = itface->first;
11006           std::set<int> oldNodes;
11007           std::set<int>::iterator itn;
11008           oldNodes.clear();
11009           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11010
11011           std::map<int, int> domvol = itface->second;
11012           std::map<int, int>::iterator itdom = domvol.begin();
11013           int dom1 = itdom->first;
11014           int vtkVolId = itdom->second;
11015           itdom++;
11016           int dom2 = itdom->first;
11017           SMDS_MeshCell *vol = grid->extrudeVolumeFromFace(vtkVolId, dom1, dom2, oldNodes, nodeDomains,
11018                                                              nodeQuadDomains);
11019           stringstream grpname;
11020           grpname << "j_";
11021           if (dom1 < dom2)
11022             grpname << dom1 << "_" << dom2;
11023           else
11024             grpname << dom2 << "_" << dom1;
11025           int idg;
11026           string namegrp = grpname.str();
11027           if (!mapOfJunctionGroups.count(namegrp))
11028             mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(vol->GetType(), namegrp.c_str(), idg);
11029           SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11030           if (sgrp)
11031             sgrp->Add(vol->GetID());
11032         }
11033     }
11034
11035   // --- create volumes on multiple domain intersection if requested
11036   //     iterate on mutipleNodesToFace
11037   //     iterate on edgesMultiDomains
11038
11039   if (createJointElems)
11040     {
11041       // --- iterate on mutipleNodesToFace
11042
11043       std::map<int, std::vector<int> >::iterator itn =  mutipleNodesToFace.begin();
11044       for (; itn != mutipleNodesToFace.end(); ++itn)
11045         {
11046           int node = itn->first;
11047           vector<int> orderDom = itn->second;
11048           vector<vtkIdType> orderedNodes;
11049           for (int idom = 0; idom <orderDom.size(); idom++)
11050             orderedNodes.push_back( nodeDomains[node][orderDom[idom]] );
11051             SMDS_MeshFace* face = this->GetMeshDS()->AddFaceFromVtkIds(orderedNodes);
11052
11053             stringstream grpname;
11054             grpname << "m2j_";
11055             grpname << 0 << "_" << 0;
11056             int idg;
11057             string namegrp = grpname.str();
11058             if (!mapOfJunctionGroups.count(namegrp))
11059               mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Face, namegrp.c_str(), idg);
11060             SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11061             if (sgrp)
11062               sgrp->Add(face->GetID());
11063         }
11064
11065       // --- iterate on edgesMultiDomains
11066
11067       std::map<std::vector<int>, std::vector<int> >::iterator ite = edgesMultiDomains.begin();
11068       for (; ite != edgesMultiDomains.end(); ++ite)
11069         {
11070           vector<int> nodes = ite->first;
11071           vector<int> orderDom = ite->second;
11072           vector<vtkIdType> orderedNodes;
11073           if (nodes.size() == 2)
11074             {
11075               //MESSAGE(" use edgesMultiDomains " << nodes[0] << " " << nodes[1]);
11076               for (int ino=0; ino < nodes.size(); ino++)
11077                 if (orderDom.size() == 3)
11078                   for (int idom = 0; idom <orderDom.size(); idom++)
11079                     orderedNodes.push_back( nodeDomains[nodes[ino]][orderDom[idom]] );
11080                 else
11081                   for (int idom = orderDom.size()-1; idom >=0; idom--)
11082                     orderedNodes.push_back( nodeDomains[nodes[ino]][orderDom[idom]] );
11083               SMDS_MeshVolume* vol = this->GetMeshDS()->AddVolumeFromVtkIds(orderedNodes);
11084
11085               stringstream grpname;
11086               grpname << "mj_";
11087               grpname << 0 << "_" << 0;
11088               int idg;
11089               string namegrp = grpname.str();
11090               if (!mapOfJunctionGroups.count(namegrp))
11091                 mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
11092               SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11093               if (sgrp)
11094                 sgrp->Add(vol->GetID());
11095             }
11096           else
11097             {
11098               MESSAGE("Quadratic multiple joints not implemented");
11099               // TODO quadratic nodes
11100             }
11101         }
11102     }
11103
11104   // --- list the explicit faces and edges of the mesh that need to be modified,
11105   //     i.e. faces and edges built with one or more duplicated nodes.
11106   //     associate these faces or edges to their corresponding domain.
11107   //     only the first domain found is kept when a face or edge is shared
11108
11109   std::map<DownIdType, std::map<int,int>, DownIdCompare> faceOrEdgeDom; // cellToModify --> (id domain --> id cell)
11110   std::map<int,int> feDom; // vtk id of cell to modify --> id domain
11111   faceOrEdgeDom.clear();
11112   feDom.clear();
11113
11114   for (int idomain = 0; idomain < theElems.size(); idomain++)
11115     {
11116       std::map<int, std::map<int, int> >::const_iterator itnod = nodeDomains.begin();
11117       for (; itnod != nodeDomains.end(); ++itnod)
11118         {
11119           int oldId = itnod->first;
11120           //MESSAGE("     node " << oldId);
11121           vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId);
11122           for (int i = 0; i < l.ncells; i++)
11123             {
11124               int vtkId = l.cells[i];
11125               int vtkType = grid->GetCellType(vtkId);
11126               int downId = grid->CellIdToDownId(vtkId);
11127               if (downId < 0)
11128                 continue; // new cells: not to be modified
11129               DownIdType aCell(downId, vtkType);
11130               int volParents[1000];
11131               int nbvol = grid->GetParentVolumes(volParents, vtkId);
11132               for (int j = 0; j < nbvol; j++)
11133                 if (celldom.count(volParents[j]) && (celldom[volParents[j]] == idomain))
11134                   if (!feDom.count(vtkId))
11135                     {
11136                       feDom[vtkId] = idomain;
11137                       faceOrEdgeDom[aCell] = emptyMap;
11138                       faceOrEdgeDom[aCell][idomain] = vtkId; // affect face or edge to the first domain only
11139                       //MESSAGE("affect cell " << this->GetMeshDS()->fromVtkToSmds(vtkId) << " domain " << idomain
11140                       //        << " type " << vtkType << " downId " << downId);
11141                     }
11142             }
11143         }
11144     }
11145
11146   // --- iterate on shared faces (volumes to modify, face to extrude)
11147   //     get node id's of the face
11148   //     replace old nodes by new nodes in volumes, and update inverse connectivity
11149
11150   std::map<DownIdType, std::map<int,int>, DownIdCompare>* maps[3] = {&faceDomains, &cellDomains, &faceOrEdgeDom};
11151   for (int m=0; m<3; m++)
11152     {
11153       std::map<DownIdType, std::map<int,int>, DownIdCompare>* amap = maps[m];
11154       itface = (*amap).begin();
11155       for (; itface != (*amap).end(); ++itface)
11156         {
11157           DownIdType face = itface->first;
11158           std::set<int> oldNodes;
11159           std::set<int>::iterator itn;
11160           oldNodes.clear();
11161           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11162           //MESSAGE("examine cell, downId " << face.cellId << " type " << int(face.cellType));
11163           std::map<int, int> localClonedNodeIds;
11164
11165           std::map<int, int> domvol = itface->second;
11166           std::map<int, int>::iterator itdom = domvol.begin();
11167           for (; itdom != domvol.end(); ++itdom)
11168             {
11169               int idom = itdom->first;
11170               int vtkVolId = itdom->second;
11171               //MESSAGE("modify nodes of cell " << this->GetMeshDS()->fromVtkToSmds(vtkVolId) << " domain " << idom);
11172               localClonedNodeIds.clear();
11173               for (itn = oldNodes.begin(); itn != oldNodes.end(); ++itn)
11174                 {
11175                   int oldId = *itn;
11176                   if (nodeDomains[oldId].count(idom))
11177                     {
11178                       localClonedNodeIds[oldId] = nodeDomains[oldId][idom];
11179                       //MESSAGE("     node " << oldId << " --> " << localClonedNodeIds[oldId]);
11180                     }
11181                 }
11182               meshDS->ModifyCellNodes(vtkVolId, localClonedNodeIds);
11183             }
11184         }
11185     }
11186
11187   meshDS->CleanDownWardConnectivity(); // Mesh has been modified, downward connectivity is no more usable, free memory
11188   grid->BuildLinks();
11189
11190   CHRONOSTOP(50);
11191   counters::stats();
11192   return true;
11193 }
11194
11195 /*!
11196  * \brief Double nodes on some external faces and create flat elements.
11197  * Flat elements are mainly used by some types of mechanic calculations.
11198  *
11199  * Each group of the list must be constituted of faces.
11200  * Triangles are transformed in prisms, and quadrangles in hexahedrons.
11201  * @param theElems - list of groups of faces, where a group of faces is a set of
11202  * SMDS_MeshElements sorted by Id.
11203  * @return TRUE if operation has been completed successfully, FALSE otherwise
11204  */
11205 bool SMESH_MeshEditor::CreateFlatElementsOnFacesGroups(const std::vector<TIDSortedElemSet>& theElems)
11206 {
11207   MESSAGE("-------------------------------------------------");
11208   MESSAGE("SMESH_MeshEditor::CreateFlatElementsOnFacesGroups");
11209   MESSAGE("-------------------------------------------------");
11210
11211   SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
11212
11213   // --- For each group of faces
11214   //     duplicate the nodes, create a flat element based on the face
11215   //     replace the nodes of the faces by their clones
11216
11217   std::map<const SMDS_MeshNode*, const SMDS_MeshNode*> clonedNodes;
11218   std::map<const SMDS_MeshNode*, const SMDS_MeshNode*> intermediateNodes;
11219   clonedNodes.clear();
11220   intermediateNodes.clear();
11221   std::map<std::string, SMESH_Group*> mapOfJunctionGroups;
11222   mapOfJunctionGroups.clear();
11223
11224   for (int idom = 0; idom < theElems.size(); idom++)
11225     {
11226       const TIDSortedElemSet& domain = theElems[idom];
11227       TIDSortedElemSet::const_iterator elemItr = domain.begin();
11228       for (; elemItr != domain.end(); ++elemItr)
11229         {
11230           SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
11231           SMDS_MeshFace* aFace = dynamic_cast<SMDS_MeshFace*> (anElem);
11232           if (!aFace)
11233             continue;
11234           // MESSAGE("aFace=" << aFace->GetID());
11235           bool isQuad = aFace->IsQuadratic();
11236           vector<const SMDS_MeshNode*> ln0, ln1, ln2, ln3, ln4;
11237
11238           // --- clone the nodes, create intermediate nodes for non medium nodes of a quad face
11239
11240           SMDS_ElemIteratorPtr nodeIt = aFace->nodesIterator();
11241           while (nodeIt->more())
11242             {
11243               const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*> (nodeIt->next());
11244               bool isMedium = isQuad && (aFace->IsMediumNode(node));
11245               if (isMedium)
11246                 ln2.push_back(node);
11247               else
11248                 ln0.push_back(node);
11249
11250               const SMDS_MeshNode* clone = 0;
11251               if (!clonedNodes.count(node))
11252                 {
11253                   clone = meshDS->AddNode(node->X(), node->Y(), node->Z());
11254                   clonedNodes[node] = clone;
11255                 }
11256               else
11257                 clone = clonedNodes[node];
11258
11259               if (isMedium)
11260                 ln3.push_back(clone);
11261               else
11262                 ln1.push_back(clone);
11263
11264               const SMDS_MeshNode* inter = 0;
11265               if (isQuad && (!isMedium))
11266                 {
11267                   if (!intermediateNodes.count(node))
11268                     {
11269                       inter = meshDS->AddNode(node->X(), node->Y(), node->Z());
11270                       intermediateNodes[node] = inter;
11271                     }
11272                   else
11273                     inter = intermediateNodes[node];
11274                   ln4.push_back(inter);
11275                 }
11276             }
11277
11278           // --- extrude the face
11279
11280           vector<const SMDS_MeshNode*> ln;
11281           SMDS_MeshVolume* vol = 0;
11282           vtkIdType aType = aFace->GetVtkType();
11283           switch (aType)
11284           {
11285             case VTK_TRIANGLE:
11286               vol = meshDS->AddVolume(ln0[2], ln0[1], ln0[0], ln1[2], ln1[1], ln1[0]);
11287               // MESSAGE("vol prism " << vol->GetID());
11288               ln.push_back(ln1[0]);
11289               ln.push_back(ln1[1]);
11290               ln.push_back(ln1[2]);
11291               break;
11292             case VTK_QUAD:
11293               vol = meshDS->AddVolume(ln0[3], ln0[2], ln0[1], ln0[0], ln1[3], ln1[2], ln1[1], ln1[0]);
11294               // MESSAGE("vol hexa " << vol->GetID());
11295               ln.push_back(ln1[0]);
11296               ln.push_back(ln1[1]);
11297               ln.push_back(ln1[2]);
11298               ln.push_back(ln1[3]);
11299               break;
11300             case VTK_QUADRATIC_TRIANGLE:
11301               vol = meshDS->AddVolume(ln1[0], ln1[1], ln1[2], ln0[0], ln0[1], ln0[2], ln3[0], ln3[1], ln3[2],
11302                                       ln2[0], ln2[1], ln2[2], ln4[0], ln4[1], ln4[2]);
11303               // MESSAGE("vol quad prism " << vol->GetID());
11304               ln.push_back(ln1[0]);
11305               ln.push_back(ln1[1]);
11306               ln.push_back(ln1[2]);
11307               ln.push_back(ln3[0]);
11308               ln.push_back(ln3[1]);
11309               ln.push_back(ln3[2]);
11310               break;
11311             case VTK_QUADRATIC_QUAD:
11312 //              vol = meshDS->AddVolume(ln0[0], ln0[1], ln0[2], ln0[3], ln1[0], ln1[1], ln1[2], ln1[3],
11313 //                                      ln2[0], ln2[1], ln2[2], ln2[3], ln3[0], ln3[1], ln3[2], ln3[3],
11314 //                                      ln4[0], ln4[1], ln4[2], ln4[3]);
11315               vol = meshDS->AddVolume(ln1[0], ln1[1], ln1[2], ln1[3], ln0[0], ln0[1], ln0[2], ln0[3],
11316                                       ln3[0], ln3[1], ln3[2], ln3[3], ln2[0], ln2[1], ln2[2], ln2[3],
11317                                       ln4[0], ln4[1], ln4[2], ln4[3]);
11318               // MESSAGE("vol quad hexa " << vol->GetID());
11319               ln.push_back(ln1[0]);
11320               ln.push_back(ln1[1]);
11321               ln.push_back(ln1[2]);
11322               ln.push_back(ln1[3]);
11323               ln.push_back(ln3[0]);
11324               ln.push_back(ln3[1]);
11325               ln.push_back(ln3[2]);
11326               ln.push_back(ln3[3]);
11327               break;
11328             case VTK_POLYGON:
11329               break;
11330             default:
11331               break;
11332           }
11333
11334           if (vol)
11335             {
11336               stringstream grpname;
11337               grpname << "jf_";
11338               grpname << idom;
11339               int idg;
11340               string namegrp = grpname.str();
11341               if (!mapOfJunctionGroups.count(namegrp))
11342                 mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
11343               SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11344               if (sgrp)
11345                 sgrp->Add(vol->GetID());
11346             }
11347
11348           // --- modify the face
11349
11350           aFace->ChangeNodes(&ln[0], ln.size());
11351         }
11352     }
11353   return true;
11354 }
11355
11356 //================================================================================
11357 /*!
11358  * \brief Generates skin mesh (containing 2D cells) from 3D mesh
11359  * The created 2D mesh elements based on nodes of free faces of boundary volumes
11360  * \return TRUE if operation has been completed successfully, FALSE otherwise
11361  */
11362 //================================================================================
11363
11364 bool SMESH_MeshEditor::Make2DMeshFrom3D()
11365 {
11366   // iterates on volume elements and detect all free faces on them
11367   SMESHDS_Mesh* aMesh = GetMeshDS();
11368   if (!aMesh)
11369     return false;
11370   //bool res = false;
11371   int nbFree = 0, nbExisted = 0, nbCreated = 0;
11372   SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator();
11373   while(vIt->more())
11374   {
11375     const SMDS_MeshVolume* volume = vIt->next();
11376     SMDS_VolumeTool vTool( volume, /*ignoreCentralNodes=*/false );
11377     vTool.SetExternalNormal();
11378     //const bool isPoly = volume->IsPoly();
11379     const int iQuad = volume->IsQuadratic();
11380     for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
11381     {
11382       if (!vTool.IsFreeFace(iface))
11383         continue;
11384       nbFree++;
11385       vector<const SMDS_MeshNode *> nodes;
11386       int nbFaceNodes = vTool.NbFaceNodes(iface);
11387       const SMDS_MeshNode** faceNodes = vTool.GetFaceNodes(iface);
11388       int inode = 0;
11389       for ( ; inode < nbFaceNodes; inode += iQuad+1)
11390         nodes.push_back(faceNodes[inode]);
11391       if (iQuad) { // add medium nodes
11392         for ( inode = 1; inode < nbFaceNodes; inode += 2)
11393           nodes.push_back(faceNodes[inode]);
11394         if ( nbFaceNodes == 9 ) // bi-quadratic quad
11395           nodes.push_back(faceNodes[8]);
11396       }
11397       // add new face based on volume nodes
11398       if (aMesh->FindElement( nodes, SMDSAbs_Face, /*noMedium=*/false) ) {
11399         nbExisted++;
11400         continue; // face already exsist
11401       }
11402       AddElement(nodes, SMDSAbs_Face, ( !iQuad && nbFaceNodes/(iQuad+1) > 4 ));
11403       nbCreated++;
11404     }
11405   }
11406   return ( nbFree==(nbExisted+nbCreated) );
11407 }
11408
11409 namespace
11410 {
11411   inline const SMDS_MeshNode* getNodeWithSameID(SMESHDS_Mesh* mesh, const SMDS_MeshNode* node)
11412   {
11413     if ( const SMDS_MeshNode* n = mesh->FindNode( node->GetID() ))
11414       return n;
11415     return mesh->AddNodeWithID( node->X(),node->Y(),node->Z(), node->GetID() );
11416   }
11417 }
11418 //================================================================================
11419 /*!
11420  * \brief Creates missing boundary elements
11421  *  \param elements - elements whose boundary is to be checked
11422  *  \param dimension - defines type of boundary elements to create
11423  *  \param group - a group to store created boundary elements in
11424  *  \param targetMesh - a mesh to store created boundary elements in
11425  *  \param toCopyElements - if true, the checked elements will be copied into the targetMesh
11426  *  \param toCopyExistingBoundary - if true, not only new but also pre-existing
11427  *                                boundary elements will be copied into the targetMesh
11428  *  \param toAddExistingBondary - if true, not only new but also pre-existing
11429  *                                boundary elements will be added into the new group
11430  *  \param aroundElements - if true, elements will be created on boundary of given
11431  *                          elements else, on boundary of the whole mesh.
11432  * \return nb of added boundary elements
11433  */
11434 //================================================================================
11435
11436 int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
11437                                        Bnd_Dimension           dimension,
11438                                        SMESH_Group*            group/*=0*/,
11439                                        SMESH_Mesh*             targetMesh/*=0*/,
11440                                        bool                    toCopyElements/*=false*/,
11441                                        bool                    toCopyExistingBoundary/*=false*/,
11442                                        bool                    toAddExistingBondary/*= false*/,
11443                                        bool                    aroundElements/*= false*/)
11444 {
11445   SMDSAbs_ElementType missType = (dimension == BND_2DFROM3D) ? SMDSAbs_Face : SMDSAbs_Edge;
11446   SMDSAbs_ElementType elemType = (dimension == BND_1DFROM2D) ? SMDSAbs_Face : SMDSAbs_Volume;
11447   // hope that all elements are of the same type, do not check them all
11448   if ( !elements.empty() && (*elements.begin())->GetType() != elemType )
11449     throw SALOME_Exception(LOCALIZED("wrong element type"));
11450
11451   if ( !targetMesh )
11452     toCopyElements = toCopyExistingBoundary = false;
11453
11454   SMESH_MeshEditor tgtEditor( targetMesh ? targetMesh : myMesh );
11455   SMESHDS_Mesh* aMesh = GetMeshDS(), *tgtMeshDS = tgtEditor.GetMeshDS();
11456   int nbAddedBnd = 0;
11457
11458   // editor adding present bnd elements and optionally holding elements to add to the group
11459   SMESH_MeshEditor* presentEditor;
11460   SMESH_MeshEditor tgtEditor2( tgtEditor.GetMesh() );
11461   presentEditor = toAddExistingBondary ? &tgtEditor : &tgtEditor2;
11462
11463   SMESH_MesherHelper helper( *myMesh );
11464   const TopAbs_ShapeEnum missShapeType = ( missType==SMDSAbs_Face ? TopAbs_FACE : TopAbs_EDGE );
11465   SMDS_VolumeTool vTool;
11466   TIDSortedElemSet avoidSet;
11467   const TIDSortedElemSet emptySet, *elemSet = aroundElements ? &elements : &emptySet;
11468   int inode;
11469
11470   typedef vector<const SMDS_MeshNode*> TConnectivity;
11471
11472   SMDS_ElemIteratorPtr eIt;
11473   if (elements.empty())
11474     eIt = aMesh->elementsIterator(elemType);
11475   else
11476     eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
11477
11478   while (eIt->more())
11479   {
11480     const SMDS_MeshElement* elem = eIt->next();
11481     const int iQuad = elem->IsQuadratic();
11482
11483     // ------------------------------------------------------------------------------------
11484     // 1. For an elem, get present bnd elements and connectivities of missing bnd elements
11485     // ------------------------------------------------------------------------------------
11486     vector<const SMDS_MeshElement*> presentBndElems;
11487     vector<TConnectivity>           missingBndElems;
11488     TConnectivity nodes;
11489     if ( vTool.Set(elem, /*ignoreCentralNodes=*/true) ) // elem is a volume --------------
11490     {
11491       vTool.SetExternalNormal();
11492       const SMDS_MeshElement* otherVol = 0;
11493       for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
11494       {
11495         if ( !vTool.IsFreeFace(iface, &otherVol) &&
11496              ( !aroundElements || elements.count( otherVol )))
11497           continue;
11498         const int nbFaceNodes = vTool.NbFaceNodes(iface);
11499         const SMDS_MeshNode** nn = vTool.GetFaceNodes(iface);
11500         if ( missType == SMDSAbs_Edge ) // boundary edges
11501         {
11502           nodes.resize( 2+iQuad );
11503           for ( int i = 0; i < nbFaceNodes; i += 1+iQuad)
11504           {
11505             for ( int j = 0; j < nodes.size(); ++j )
11506               nodes[j] =nn[i+j];
11507             if ( const SMDS_MeshElement* edge =
11508                  aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/false))
11509               presentBndElems.push_back( edge );
11510             else
11511               missingBndElems.push_back( nodes );
11512           }
11513         }
11514         else // boundary face
11515         {
11516           nodes.clear();
11517           for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
11518             nodes.push_back( nn[inode] );
11519           if (iQuad) // add medium nodes
11520             for ( inode = 1; inode < nbFaceNodes; inode += 2)
11521               nodes.push_back( nn[inode] );
11522           int iCenter = vTool.GetCenterNodeIndex(iface); // for HEX27
11523           if ( iCenter > 0 )
11524             nodes.push_back( vTool.GetNodes()[ iCenter ] );
11525
11526           if (const SMDS_MeshElement * f = aMesh->FindElement( nodes,
11527                                                                SMDSAbs_Face, /*noMedium=*/false ))
11528             presentBndElems.push_back( f );
11529           else
11530             missingBndElems.push_back( nodes );
11531
11532           if ( targetMesh != myMesh )
11533           {
11534             // add 1D elements on face boundary to be added to a new mesh
11535             const SMDS_MeshElement* edge;
11536             for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
11537             {
11538               if ( iQuad )
11539                 edge = aMesh->FindEdge( nn[inode], nn[inode+1], nn[inode+2]);
11540               else
11541                 edge = aMesh->FindEdge( nn[inode], nn[inode+1]);
11542               if ( edge && avoidSet.insert( edge ).second )
11543                 presentBndElems.push_back( edge );
11544             }
11545           }
11546         }
11547       }
11548     }
11549     else                     // elem is a face ------------------------------------------
11550     {
11551       avoidSet.clear(), avoidSet.insert( elem );
11552       int nbNodes = elem->NbCornerNodes();
11553       nodes.resize( 2 /*+ iQuad*/);
11554       for ( int i = 0; i < nbNodes; i++ )
11555       {
11556         nodes[0] = elem->GetNode(i);
11557         nodes[1] = elem->GetNode((i+1)%nbNodes);
11558         if ( FindFaceInSet( nodes[0], nodes[1], *elemSet, avoidSet))
11559           continue; // not free link
11560
11561         //if ( iQuad )
11562         //nodes[2] = elem->GetNode( i + nbNodes );
11563         if ( const SMDS_MeshElement* edge =
11564              aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/true))
11565           presentBndElems.push_back( edge );
11566         else
11567           missingBndElems.push_back( nodes );
11568       }
11569     }
11570
11571     // ---------------------------------
11572     // 2. Add missing boundary elements
11573     // ---------------------------------
11574     if ( targetMesh != myMesh )
11575       // instead of making a map of nodes in this mesh and targetMesh,
11576       // we create nodes with same IDs.
11577       for ( int i = 0; i < missingBndElems.size(); ++i )
11578       {
11579         TConnectivity& srcNodes = missingBndElems[i];
11580         TConnectivity  nodes( srcNodes.size() );
11581         for ( inode = 0; inode < nodes.size(); ++inode )
11582           nodes[inode] = getNodeWithSameID( tgtMeshDS, srcNodes[inode] );
11583         if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes,
11584                                                                    missType,
11585                                                                    /*noMedium=*/false))
11586           continue;
11587         tgtEditor.AddElement(nodes, missType, !iQuad && nodes.size()/(iQuad+1)>4);
11588         ++nbAddedBnd;
11589       }
11590     else
11591       for ( int i = 0; i < missingBndElems.size(); ++i )
11592       {
11593         TConnectivity& nodes = missingBndElems[i];
11594         if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes,
11595                                                                    missType,
11596                                                                    /*noMedium=*/false))
11597           continue;
11598         SMDS_MeshElement* elem = 
11599           tgtEditor.AddElement(nodes, missType, !iQuad && nodes.size()/(iQuad+1)>4);
11600         ++nbAddedBnd;
11601
11602         // try to set a new element to a shape
11603         if ( myMesh->HasShapeToMesh() )
11604         {
11605           bool ok = true;
11606           set< pair<TopAbs_ShapeEnum, int > > mediumShapes;
11607           const int nbN = nodes.size() / (iQuad+1 );
11608           for ( inode = 0; inode < nbN && ok; ++inode )
11609           {
11610             pair<int, TopAbs_ShapeEnum> i_stype =
11611               helper.GetMediumPos( nodes[inode], nodes[(inode+1)%nbN]);
11612             if (( ok = ( i_stype.first > 0 && i_stype.second >= TopAbs_FACE )))
11613               mediumShapes.insert( make_pair ( i_stype.second, i_stype.first ));
11614           }
11615           if ( ok && mediumShapes.size() > 1 )
11616           {
11617             set< pair<TopAbs_ShapeEnum, int > >::iterator stype_i = mediumShapes.begin();
11618             pair<TopAbs_ShapeEnum, int> stype_i_0 = *stype_i;
11619             for ( ++stype_i; stype_i != mediumShapes.end() && ok; ++stype_i )
11620             {
11621               if (( ok = ( stype_i->first != stype_i_0.first )))
11622                 ok = helper.IsSubShape( aMesh->IndexToShape( stype_i->second ),
11623                                         aMesh->IndexToShape( stype_i_0.second ));
11624             }
11625           }
11626           if ( ok && mediumShapes.begin()->first == missShapeType )
11627             aMesh->SetMeshElementOnShape( elem, mediumShapes.begin()->second );
11628         }
11629       }
11630
11631     // ----------------------------------
11632     // 3. Copy present boundary elements
11633     // ----------------------------------
11634     if ( toCopyExistingBoundary )
11635       for ( int i = 0 ; i < presentBndElems.size(); ++i )
11636       {
11637         const SMDS_MeshElement* e = presentBndElems[i];
11638         TConnectivity nodes( e->NbNodes() );
11639         for ( inode = 0; inode < nodes.size(); ++inode )
11640           nodes[inode] = getNodeWithSameID( tgtMeshDS, e->GetNode(inode) );
11641         presentEditor->AddElement(nodes, e->GetType(), e->IsPoly());
11642       }
11643     else // store present elements to add them to a group
11644       for ( int i = 0 ; i < presentBndElems.size(); ++i )
11645       {
11646         presentEditor->myLastCreatedElems.Append(presentBndElems[i]);
11647       }
11648       
11649   } // loop on given elements
11650
11651   // ---------------------------------------------
11652   // 4. Fill group with boundary elements
11653   // ---------------------------------------------
11654   if ( group )
11655   {
11656     if ( SMESHDS_Group* g = dynamic_cast<SMESHDS_Group*>( group->GetGroupDS() ))
11657       for ( int i = 0; i < tgtEditor.myLastCreatedElems.Size(); ++i )
11658         g->SMDSGroup().Add( tgtEditor.myLastCreatedElems( i+1 ));
11659   }
11660   tgtEditor.myLastCreatedElems.Clear();
11661   tgtEditor2.myLastCreatedElems.Clear();
11662
11663   // -----------------------
11664   // 5. Copy given elements
11665   // -----------------------
11666   if ( toCopyElements && targetMesh != myMesh )
11667   {
11668     if (elements.empty())
11669       eIt = aMesh->elementsIterator(elemType);
11670     else
11671       eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
11672     while (eIt->more())
11673     {
11674       const SMDS_MeshElement* elem = eIt->next();
11675       TConnectivity nodes( elem->NbNodes() );
11676       for ( inode = 0; inode < nodes.size(); ++inode )
11677         nodes[inode] = getNodeWithSameID( tgtMeshDS, elem->GetNode(inode) );
11678       tgtEditor.AddElement(nodes, elemType, elem->IsPoly());
11679
11680       tgtEditor.myLastCreatedElems.Clear();
11681     }
11682   }
11683   return nbAddedBnd;
11684 }