Salome HOME
Enable splitting bi-quad quadrangles by QuadToTri()
[modules/smesh.git] / src / SMESH_I / SMESH_MeshEditor_i.cxx
1 // Copyright (C) 2007-2015  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, or (at your option) any later version.
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 //  File   : SMESH_MeshEditor_i.cxx
23 //  Author : Nicolas REJNERI
24 //  Module : SMESH
25
26 #ifdef WIN32
27 #define NOMINMAX
28 #endif
29
30 // A macro used in SMESH_TryCatch.hxx,
31 // it re-raises a CORBA SALOME exception thrown by SMESH_MeshEditor_i and caught by SMESH_CATCH
32 #define SMY_OWN_CATCH \
33   catch ( SALOME::SALOME_Exception & e ) { throw e; }
34
35 #include "SMESH_MeshEditor_i.hxx"
36
37 #include "SMDS_EdgePosition.hxx"
38 #include "SMDS_ElemIterator.hxx"
39 #include "SMDS_FacePosition.hxx"
40 #include "SMDS_IteratorOnIterators.hxx"
41 #include "SMDS_LinearEdge.hxx"
42 #include "SMDS_Mesh0DElement.hxx"
43 #include "SMDS_MeshFace.hxx"
44 #include "SMDS_MeshVolume.hxx"
45 #include "SMDS_PolyhedralVolumeOfNodes.hxx"
46 #include "SMDS_SetIterator.hxx"
47 #include "SMDS_VolumeTool.hxx"
48 #include "SMESHDS_Group.hxx"
49 #include "SMESHDS_GroupOnGeom.hxx"
50 #include "SMESH_ControlsDef.hxx"
51 #include "SMESH_Filter_i.hxx"
52 #include "SMESH_Gen_i.hxx"
53 #include "SMESH_Group.hxx"
54 #include "SMESH_Group_i.hxx"
55 #include "SMESH_MeshAlgos.hxx"
56 #include "SMESH_MeshPartDS.hxx"
57 #include "SMESH_MesherHelper.hxx"
58 #include "SMESH_PythonDump.hxx"
59 #include "SMESH_subMeshEventListener.hxx"
60 #include "SMESH_subMesh_i.hxx"
61
62 #include <utilities.h>
63 #include <Utils_ExceptHandlers.hxx>
64 #include <Utils_CorbaException.hxx>
65 #include <SALOMEDS_wrap.hxx>
66 #include <SALOME_GenericObj_i.hh>
67 #include <Basics_OCCTVersion.hxx>
68
69 #include <BRepAdaptor_Surface.hxx>
70 #include <BRep_Tool.hxx>
71 #include <TopExp_Explorer.hxx>
72 #include <TopoDS.hxx>
73 #include <TopoDS_Edge.hxx>
74 #include <TopoDS_Face.hxx>
75 #include <gp_Ax1.hxx>
76 #include <gp_Ax2.hxx>
77 #include <gp_Vec.hxx>
78
79 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
80 #define NO_CAS_CATCH
81 #endif
82
83 #include <Standard_Failure.hxx>
84
85 #ifdef NO_CAS_CATCH
86 #include <Standard_ErrorHandler.hxx>
87 #endif
88
89 #include <sstream>
90 #include <limits>
91
92 #include "SMESH_TryCatch.hxx" // include after OCCT headers!
93
94 #define cast2Node(elem) static_cast<const SMDS_MeshNode*>( elem )
95
96 using namespace std;
97 using SMESH::TPythonDump;
98 using SMESH::TVar;
99
100 namespace MeshEditor_I {
101
102   //=============================================================================
103   /*!
104    * \brief Mesh to apply modifications for preview purposes
105    */
106   //=============================================================================
107
108   struct TPreviewMesh: public SMESH_Mesh
109   {
110     SMDSAbs_ElementType myPreviewType; // type to show
111     //!< Constructor
112     TPreviewMesh(SMDSAbs_ElementType previewElements = SMDSAbs_All) {
113       _isShapeToMesh = (_id =_studyId = 0);
114       _myMeshDS  = new SMESHDS_Mesh( _id, true );
115       myPreviewType = previewElements;
116     }
117     //!< Copy a set of elements
118     void Copy(const TIDSortedElemSet & theElements,
119               TIDSortedElemSet&        theCopyElements,
120               SMDSAbs_ElementType      theSelectType = SMDSAbs_All,
121               SMDSAbs_ElementType      theAvoidType = SMDSAbs_All)
122     {
123       // loop on theIDsOfElements
124       TIDSortedElemSet::const_iterator eIt = theElements.begin();
125       for ( ; eIt != theElements.end(); ++eIt )
126       {
127         const SMDS_MeshElement* anElem = *eIt;
128         if ( !anElem ) continue;
129         SMDSAbs_ElementType type = anElem->GetType();
130         if ( type == theAvoidType ||
131              ( theSelectType != SMDSAbs_All && type != theSelectType ))
132           continue;
133         const SMDS_MeshElement* anElemCopy;
134         if ( type == SMDSAbs_Node)
135           anElemCopy = Copy( cast2Node(anElem) );
136         else
137           anElemCopy = Copy( anElem );
138         if ( anElemCopy )
139           theCopyElements.insert( theCopyElements.end(), anElemCopy );
140       }
141     }
142     //!< Copy an element
143     SMDS_MeshElement* Copy( const SMDS_MeshElement* anElem )
144     {
145       // copy element nodes
146       int anElemNbNodes = anElem->NbNodes();
147       vector< int > anElemNodesID( anElemNbNodes ) ;
148       SMDS_ElemIteratorPtr itElemNodes = anElem->nodesIterator();
149       for ( int i = 0; itElemNodes->more(); i++)
150       {
151         const SMDS_MeshNode* anElemNode = cast2Node( itElemNodes->next() );
152         Copy( anElemNode );
153         anElemNodesID[i] = anElemNode->GetID();
154       }
155
156       // creates a corresponding element on copied nodes
157       ::SMESH_MeshEditor::ElemFeatures elemType;
158       elemType.Init( anElem, /*basicOnly=*/false );
159       elemType.SetID( anElem->GetID() );
160       SMDS_MeshElement* anElemCopy =
161         ::SMESH_MeshEditor(this).AddElement( anElemNodesID, elemType );
162       return anElemCopy;
163     }
164     //!< Copy a node
165     SMDS_MeshNode* Copy( const SMDS_MeshNode* anElemNode )
166     {
167       return _myMeshDS->AddNodeWithID(anElemNode->X(), anElemNode->Y(), anElemNode->Z(),
168                                       anElemNode->GetID());
169     }
170     void RemoveAll()
171     {
172       GetMeshDS()->ClearMesh();
173     }
174     void Remove( SMDSAbs_ElementType type )
175     {
176       SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator( type );
177       while ( eIt->more() )
178         GetMeshDS()->RemoveFreeElement( eIt->next(), /*sm=*/0, /*fromGroups=*/false );
179     }
180   };// struct TPreviewMesh
181
182   static SMESH_NodeSearcher *    theNodeSearcher    = 0;
183   static SMESH_ElementSearcher * theElementSearcher = 0;
184
185   //=============================================================================
186   /*!
187    * \brief Deleter of theNodeSearcher at any compute event occured
188    */
189   //=============================================================================
190
191   struct TSearchersDeleter : public SMESH_subMeshEventListener
192   {
193     SMESH_Mesh* myMesh;
194     string      myMeshPartIOR;
195     //!< Constructor
196     TSearchersDeleter(): SMESH_subMeshEventListener( false, // won't be deleted by submesh
197                                                      "SMESH_MeshEditor_i::TSearchersDeleter"),
198                          myMesh(0) {}
199     //!< Delete theNodeSearcher
200     static void Delete()
201     {
202       if ( theNodeSearcher )    delete theNodeSearcher;    theNodeSearcher    = 0;
203       if ( theElementSearcher ) delete theElementSearcher; theElementSearcher = 0;
204     }
205     typedef map < int, SMESH_subMesh * > TDependsOnMap;
206     //!< The meshod called by submesh: do my main job
207     void ProcessEvent(const int, const int eventType, SMESH_subMesh* sm,
208                       SMESH_subMeshEventListenerData*,const SMESH_Hypothesis*)
209     {
210       if ( eventType == SMESH_subMesh::COMPUTE_EVENT ) {
211         Delete();
212         Unset( sm->GetFather() );
213       }
214     }
215     //!< set self on all submeshes and delete theNodeSearcher if other mesh is set
216     void Set(SMESH_Mesh* mesh, const string& meshPartIOR = string())
217     {
218       if ( myMesh != mesh || myMeshPartIOR != meshPartIOR)
219       {
220         if ( myMesh ) {
221           Delete();
222           Unset( myMesh );
223         }
224         myMesh = mesh;
225         myMeshPartIOR = meshPartIOR;
226         SMESH_subMesh* sm = mesh->GetSubMesh( mesh->GetShapeToMesh() );
227         SMESH_subMeshIteratorPtr smIt = sm->getDependsOnIterator( /*includeSelf=*/true );
228         while ( smIt->more() )
229         {
230           sm = smIt->next();
231           sm->SetEventListener( this, 0, sm );
232         }
233       }
234     }
235     //!<  delete self from all submeshes
236     void Unset(SMESH_Mesh* mesh)
237     {
238       if ( SMESH_subMesh* sm = mesh->GetSubMeshContaining(1) ) {
239         SMESH_subMeshIteratorPtr smIt = sm->getDependsOnIterator( /*includeSelf=*/true );
240         while ( smIt->more() )
241           smIt->next()->DeleteEventListener( this );
242       }
243       myMesh = 0;
244     }
245
246   } theSearchersDeleter;
247
248   TCollection_AsciiString mirrorTypeName( SMESH::SMESH_MeshEditor::MirrorType theMirrorType )
249   {
250     TCollection_AsciiString typeStr;
251     switch ( theMirrorType ) {
252     case  SMESH::SMESH_MeshEditor::POINT:
253       typeStr = "SMESH.SMESH_MeshEditor.POINT";
254       break;
255     case  SMESH::SMESH_MeshEditor::AXIS:
256       typeStr = "SMESH.SMESH_MeshEditor.AXIS";
257       break;
258     default:
259       typeStr = "SMESH.SMESH_MeshEditor.PLANE";
260     }
261     return typeStr;
262   }
263   //================================================================================
264   /*!
265    * \brief function for conversion of long_array to TIDSortedElemSet
266    * \param IDs - array of IDs
267    * \param aMesh - mesh
268    * \param aMap - collection to fill
269    * \param aType - element type
270    */
271   //================================================================================
272
273   void arrayToSet(const SMESH::long_array & IDs,
274                   const SMESHDS_Mesh*       aMesh,
275                   TIDSortedElemSet&         aMap,
276                   const SMDSAbs_ElementType aType = SMDSAbs_All,
277                   SMDS_MeshElement::Filter* aFilter = NULL)
278   {
279     SMDS_MeshElement::NonNullFilter filter1;
280     SMDS_MeshElement::TypeFilter    filter2( aType );
281
282     if ( aFilter == NULL )
283       aFilter = ( aType == SMDSAbs_All ) ? (SMDS_MeshElement::Filter*) &filter1 : (SMDS_MeshElement::Filter*) &filter2;
284     
285     SMDS_MeshElement::Filter & filter = *aFilter;
286
287     if ( aType == SMDSAbs_Node )
288       for ( CORBA::ULong i = 0; i < IDs.length(); i++ ) {
289         const SMDS_MeshElement * elem = aMesh->FindNode( IDs[i] );
290         if ( filter( elem ))
291           aMap.insert( aMap.end(), elem );
292       }
293     else
294       for ( CORBA::ULong i = 0; i<IDs.length(); i++) {
295         const SMDS_MeshElement * elem = aMesh->FindElement( IDs[i] );
296         if ( filter( elem ))
297           aMap.insert( aMap.end(), elem );
298       }
299   }
300
301   //================================================================================
302   /*!
303    * \brief Retrieve nodes from SMESH_IDSource
304    */
305   //================================================================================
306
307   void idSourceToNodeSet(SMESH::SMESH_IDSource_ptr  theObject,
308                          const SMESHDS_Mesh*        theMeshDS,
309                          TIDSortedNodeSet&          theNodeSet)
310
311   {
312     if ( CORBA::is_nil( theObject ) )
313       return;
314     SMESH::array_of_ElementType_var types = theObject->GetTypes();
315     SMESH::long_array_var     aElementsId = theObject->GetIDs();
316     if ( types->length() == 1 && types[0] == SMESH::NODE)
317     {
318       for ( CORBA::ULong i = 0; i < aElementsId->length(); i++ )
319         if ( const SMDS_MeshNode * n = theMeshDS->FindNode( aElementsId[i] ))
320           theNodeSet.insert( theNodeSet.end(), n);
321     }
322     else if ( SMESH::DownCast<SMESH_Mesh_i*>( theObject ))
323     {
324       SMDS_NodeIteratorPtr nIt = theMeshDS->nodesIterator();
325       while ( nIt->more( ))
326         if ( const SMDS_MeshElement * elem = nIt->next() )
327           theNodeSet.insert( elem->begin_nodes(), elem->end_nodes());
328     }
329     else
330     {
331       for ( CORBA::ULong i = 0; i < aElementsId->length(); i++ )
332         if ( const SMDS_MeshElement * elem = theMeshDS->FindElement( aElementsId[i] ))
333           theNodeSet.insert( elem->begin_nodes(), elem->end_nodes());
334     }
335   }
336
337   //================================================================================
338   /*!
339    * \brief Returns elements connected to the given elements
340    */
341   //================================================================================
342
343   void getElementsAround(const TIDSortedElemSet& theElements,
344                          const SMESHDS_Mesh*     theMeshDS,
345                          TIDSortedElemSet&       theElementsAround)
346   {
347     if ( theElements.empty() ) return;
348
349     SMDSAbs_ElementType elemType    = (*theElements.begin())->GetType();
350     bool sameElemType = ( elemType == (*theElements.rbegin())->GetType() );
351     if ( sameElemType &&
352          theMeshDS->GetMeshInfo().NbElements( elemType ) == (int) theElements.size() )
353       return; // all the elements are in theElements
354
355     if ( !sameElemType )
356       elemType = SMDSAbs_All;
357
358     vector<bool> isNodeChecked( theMeshDS->NbNodes(), false );
359
360     TIDSortedElemSet::const_iterator elemIt = theElements.begin();
361     for ( ; elemIt != theElements.end(); ++elemIt )
362     {
363       const SMDS_MeshElement* e = *elemIt;
364       int i = e->NbCornerNodes();
365       while ( --i != -1 )
366       {
367         const SMDS_MeshNode* n = e->GetNode( i );
368         if ( !isNodeChecked[ n->GetID() ])
369         {
370           isNodeChecked[ n->GetID() ] = true;
371           SMDS_ElemIteratorPtr invIt = n->GetInverseElementIterator(elemType);
372           while ( invIt->more() )
373           {
374             const SMDS_MeshElement* elemAround = invIt->next();
375             if ( !theElements.count( elemAround ))
376               theElementsAround.insert( elemAround );
377           }
378         }
379       }
380     }
381   }
382
383   //================================================================================
384   /*!
385    * \brief Return a string used to detect change of mesh part on which theElementSearcher
386    * is going to be used
387    */
388   //================================================================================
389
390   string getPartIOR( SMESH::SMESH_IDSource_ptr theMeshPart, SMESH::ElementType type)
391   {
392     string partIOR = SMESH_Gen_i::GetORB()->object_to_string( theMeshPart );
393     if ( SMESH_Group_i* group_i = SMESH::DownCast<SMESH_Group_i*>( theMeshPart ))
394       // take into account passible group modification
395       partIOR += SMESH_Comment( ((SMESHDS_Group*)group_i->GetGroupDS())->SMDSGroup().Tic() );
396     partIOR += SMESH_Comment( type );
397     return partIOR;
398   }
399
400 } // namespace MeshEditor_I
401
402 using namespace MeshEditor_I;
403
404 //=============================================================================
405 /*!
406  *
407  */
408 //=============================================================================
409
410 SMESH_MeshEditor_i::SMESH_MeshEditor_i(SMESH_Mesh_i* theMesh, bool isPreview):
411   myMesh_i( theMesh ),
412   myMesh( &theMesh->GetImpl() ),
413   myEditor( myMesh ),
414   myIsPreviewMode ( isPreview ),
415   myPreviewMesh( 0 ),
416   myPreviewEditor( 0 )
417 {
418 }
419
420 //================================================================================
421 /*!
422  * \brief Destructor
423  */
424 //================================================================================
425
426 SMESH_MeshEditor_i::~SMESH_MeshEditor_i()
427 {
428   PortableServer::POA_var poa = SMESH_Gen_i::GetPOA();
429   PortableServer::ObjectId_var anObjectId = poa->servant_to_id(this);
430   poa->deactivate_object(anObjectId.in());
431
432   //deleteAuxIDSources();
433   delete myPreviewMesh;   myPreviewMesh = 0;
434   delete myPreviewEditor; myPreviewEditor = 0;
435 }
436
437 //================================================================================
438 /*!
439  * \brief Returns the mesh
440  */
441 //================================================================================
442
443 SMESH::SMESH_Mesh_ptr SMESH_MeshEditor_i::GetMesh()
444 {
445   return myMesh_i->_this();
446 }
447
448 //================================================================================
449 /*!
450  * \brief Clear members
451  */
452 //================================================================================
453
454 void SMESH_MeshEditor_i::initData(bool deleteSearchers)
455 {
456   if ( myIsPreviewMode ) {
457     if ( myPreviewMesh ) myPreviewMesh->RemoveAll();
458   }
459   else {
460     if ( deleteSearchers )
461       TSearchersDeleter::Delete();
462   }
463   getEditor().GetError().reset();
464   getEditor().ClearLastCreated();
465 }
466
467 //================================================================================
468 /*!
469  * \brief Increment mesh modif time and optionally record that the performed
470  *        modification may influence futher mesh re-compute.
471  *  \param [in] isReComputeSafe - true if the modification does not influence
472  *              futher mesh re-compute
473  */
474 //================================================================================
475
476 void SMESH_MeshEditor_i::declareMeshModified( bool isReComputeSafe )
477 {
478   myMesh->GetMeshDS()->Modified();
479   if ( !isReComputeSafe )
480     myMesh->SetIsModified( true );
481 }
482
483 //================================================================================
484 /*!
485  * \brief Return either myEditor or myPreviewEditor depending on myIsPreviewMode.
486  *        WARNING: in preview mode call getPreviewMesh() before getEditor()!
487  */
488 //================================================================================
489
490 ::SMESH_MeshEditor& SMESH_MeshEditor_i::getEditor()
491 {
492   if ( myIsPreviewMode && !myPreviewEditor ) {
493     if ( !myPreviewMesh ) getPreviewMesh();
494     myPreviewEditor = new ::SMESH_MeshEditor( myPreviewMesh );
495   }
496   return myIsPreviewMode ? *myPreviewEditor : myEditor;
497 }
498
499 //================================================================================
500 /*!
501  * \brief Initialize and return myPreviewMesh
502  *  \param previewElements - type of elements to show in preview
503  *
504  *  WARNING: call it once par a method!
505  */
506 //================================================================================
507
508 TPreviewMesh * SMESH_MeshEditor_i::getPreviewMesh(SMDSAbs_ElementType previewElements)
509 {
510   if ( !myPreviewMesh || myPreviewMesh->myPreviewType != previewElements )
511   {
512     delete myPreviewEditor;
513     myPreviewEditor = 0;
514     delete myPreviewMesh;
515     myPreviewMesh = new TPreviewMesh( previewElements );
516   }
517   myPreviewMesh->Clear();
518   return myPreviewMesh;
519 }
520
521 //================================================================================
522 /*!
523  * Return data of mesh edition preview
524  */
525 //================================================================================
526
527 SMESH::MeshPreviewStruct* SMESH_MeshEditor_i::GetPreviewData()
528   throw (SALOME::SALOME_Exception)
529 {
530   SMESH_TRY;
531   const bool hasBadElems = ( getEditor().GetError() && getEditor().GetError()->HasBadElems() );
532
533   if ( myIsPreviewMode || hasBadElems ) { // --- MeshPreviewStruct filling ---
534
535     list<int> aNodesConnectivity;
536     typedef map<int, int> TNodesMap;
537     TNodesMap nodesMap;
538
539     SMESHDS_Mesh* aMeshDS;
540     std::auto_ptr< SMESH_MeshPartDS > aMeshPartDS;
541     if ( hasBadElems ) {
542       aMeshPartDS.reset( new SMESH_MeshPartDS( getEditor().GetError()->myBadElements ));
543       aMeshDS = aMeshPartDS.get();
544     }
545     else {
546       aMeshDS = getEditor().GetMeshDS();
547     }
548     myPreviewData = new SMESH::MeshPreviewStruct();
549     myPreviewData->nodesXYZ.length(aMeshDS->NbNodes());
550
551
552     SMDSAbs_ElementType previewType = SMDSAbs_All;
553     if ( !hasBadElems )
554       if (TPreviewMesh * aPreviewMesh = dynamic_cast< TPreviewMesh* >( getEditor().GetMesh() )) {
555         previewType = aPreviewMesh->myPreviewType;
556         switch ( previewType ) {
557         case SMDSAbs_Edge  : break;
558         case SMDSAbs_Face  : break;
559         case SMDSAbs_Volume: break;
560         default:;
561           if ( aMeshDS->GetMeshInfo().NbElements() == 0 ) previewType = SMDSAbs_Node;
562         }
563       }
564
565     myPreviewData->elementTypes.length( aMeshDS->GetMeshInfo().NbElements( previewType ));
566     int i = 0, j = 0;
567     SMDS_ElemIteratorPtr itMeshElems = aMeshDS->elementsIterator(previewType);
568
569     while ( itMeshElems->more() ) {
570       const SMDS_MeshElement* aMeshElem = itMeshElems->next();
571       SMDS_NodeIteratorPtr itElemNodes = 
572         (( aMeshElem->GetEntityType() == SMDSEntity_Quad_Polygon ) ?
573          aMeshElem->interlacedNodesIterator() :
574          aMeshElem->nodeIterator() );
575       while ( itElemNodes->more() ) {
576         const SMDS_MeshNode* aMeshNode = itElemNodes->next();
577         int aNodeID = aMeshNode->GetID();
578         TNodesMap::iterator anIter = nodesMap.find(aNodeID);
579         if ( anIter == nodesMap.end() ) {
580           // filling the nodes coordinates
581           myPreviewData->nodesXYZ[j].x = aMeshNode->X();
582           myPreviewData->nodesXYZ[j].y = aMeshNode->Y();
583           myPreviewData->nodesXYZ[j].z = aMeshNode->Z();
584           anIter = nodesMap.insert( make_pair(aNodeID, j) ).first;
585           j++;
586         }
587         aNodesConnectivity.push_back(anIter->second);
588       }
589
590       // filling the elements types
591       SMDSAbs_ElementType aType = aMeshElem->GetType();
592       bool               isPoly = aMeshElem->IsPoly();
593       myPreviewData->elementTypes[i].SMDS_ElementType = (SMESH::ElementType) aType;
594       myPreviewData->elementTypes[i].isPoly           = isPoly;
595       myPreviewData->elementTypes[i].nbNodesInElement = aMeshElem->NbNodes();
596       i++;
597     }
598     myPreviewData->nodesXYZ.length( j );
599
600     // filling the elements connectivities
601     list<int>::iterator aConnIter = aNodesConnectivity.begin();
602     myPreviewData->elementConnectivities.length(aNodesConnectivity.size());
603     for( int i = 0; aConnIter != aNodesConnectivity.end(); aConnIter++, i++ )
604       myPreviewData->elementConnectivities[i] = *aConnIter;
605   }
606   return myPreviewData._retn();
607
608   SMESH_CATCH( SMESH::throwCorbaException );
609   return 0;
610 }
611
612 //================================================================================
613 /*!
614  * \brief Returns list of it's IDs of created nodes
615  * \retval SMESH::long_array* - list of node ID
616  */
617 //================================================================================
618
619 SMESH::long_array* SMESH_MeshEditor_i::GetLastCreatedNodes()
620   throw (SALOME::SALOME_Exception)
621 {
622   SMESH_TRY;
623   SMESH::long_array_var myLastCreatedNodes = new SMESH::long_array();
624
625   const SMESH_SequenceOfElemPtr& aSeq = getEditor().GetLastCreatedNodes();
626   myLastCreatedNodes->length( aSeq.Length() );
627   for (int i = 1; i <= aSeq.Length(); i++)
628     myLastCreatedNodes[i-1] = aSeq.Value(i)->GetID();
629
630   return myLastCreatedNodes._retn();
631   SMESH_CATCH( SMESH::throwCorbaException );
632   return 0;
633 }
634
635 //================================================================================
636 /*!
637  * \brief Returns list of it's IDs of created elements
638  * \retval SMESH::long_array* - list of elements' ID
639  */
640 //================================================================================
641
642 SMESH::long_array* SMESH_MeshEditor_i::GetLastCreatedElems()
643   throw (SALOME::SALOME_Exception)
644 {
645   SMESH_TRY;
646   SMESH::long_array_var myLastCreatedElems = new SMESH::long_array();
647
648   const SMESH_SequenceOfElemPtr& aSeq = getEditor().GetLastCreatedElems();
649   myLastCreatedElems->length( aSeq.Length() );
650   for ( int i = 1; i <= aSeq.Length(); i++ )
651     myLastCreatedElems[i-1] = aSeq.Value(i)->GetID();
652
653   return myLastCreatedElems._retn();
654   SMESH_CATCH( SMESH::throwCorbaException );
655   return 0;
656 }
657
658 //=======================================================================
659 //function : ClearLastCreated
660 //purpose  : Clears sequences of last created elements and nodes 
661 //=======================================================================
662
663 void SMESH_MeshEditor_i::ClearLastCreated() throw (SALOME::SALOME_Exception)
664 {
665   SMESH_TRY;
666   getEditor().ClearLastCreated();
667   SMESH_CATCH( SMESH::throwCorbaException );
668 }
669
670 //=======================================================================
671 /*
672  * Returns description of an error/warning occured during the last operation
673  * WARNING: ComputeError.code >= 100 and no corresponding enum in IDL API
674  */
675 //=======================================================================
676
677 SMESH::ComputeError* SMESH_MeshEditor_i::GetLastError()
678   throw (SALOME::SALOME_Exception)
679 {
680   SMESH_TRY;
681   SMESH::ComputeError_var errOut = new SMESH::ComputeError;
682   SMESH_ComputeErrorPtr&  errIn  = getEditor().GetError();
683   if ( errIn && !errIn->IsOK() )
684   {
685     errOut->code       = -( errIn->myName < 0 ? errIn->myName + 1: errIn->myName ); // -1 -> 0
686     errOut->comment    = errIn->myComment.c_str();
687     errOut->subShapeID = -1;
688     errOut->hasBadMesh = !errIn->myBadElements.empty();
689   }
690   else
691   {
692     errOut->code       = 0;
693     errOut->subShapeID = -1;
694     errOut->hasBadMesh = false;
695   }
696
697   return errOut._retn();
698   SMESH_CATCH( SMESH::throwCorbaException );
699   return 0;
700 }
701
702 //=======================================================================
703 //function : MakeIDSource
704 //purpose  : Wrap a sequence of ids in a SMESH_IDSource.
705 //           Call UnRegister() as you fininsh using it!!
706 //=======================================================================
707
708 struct SMESH_MeshEditor_i::_IDSource : public virtual POA_SMESH::SMESH_IDSource,
709                                        public virtual SALOME::GenericObj_i
710 {
711   SMESH::long_array     _ids;
712   SMESH::ElementType    _type;
713   SMESH::SMESH_Mesh_ptr _mesh;
714   SMESH::long_array* GetIDs()      { return new SMESH::long_array( _ids ); }
715   SMESH::long_array* GetMeshInfo() { return 0; }
716   SMESH::long_array* GetNbElementsByType()
717   {
718     SMESH::long_array_var aRes = new SMESH::long_array();
719     aRes->length(SMESH::NB_ELEMENT_TYPES);
720     for (int i = 0; i < SMESH::NB_ELEMENT_TYPES; i++)
721       aRes[ i ] = ( i == _type ) ? _ids.length() : 0;
722     return aRes._retn();  
723   }
724   SMESH::SMESH_Mesh_ptr GetMesh()  { return SMESH::SMESH_Mesh::_duplicate( _mesh ); }
725   bool IsMeshInfoCorrect()         { return true; }
726   SMESH::array_of_ElementType* GetTypes()
727   {
728     SMESH::array_of_ElementType_var types = new SMESH::array_of_ElementType;
729     if ( _ids.length() > 0 ) {
730       types->length( 1 );
731       types[0] = _type;
732     }
733     return types._retn();
734   }
735   SALOMEDS::TMPFile* GetVtkUgStream()
736   {
737     SALOMEDS::TMPFile_var SeqFile;
738     return SeqFile._retn();
739   }
740 };
741
742 SMESH::SMESH_IDSource_ptr SMESH_MeshEditor_i::MakeIDSource(const SMESH::long_array& ids,
743                                                            SMESH::ElementType       type)
744 {
745   _IDSource* idSrc = new _IDSource;
746   idSrc->_mesh = myMesh_i->_this();
747   idSrc->_ids  = ids;
748   idSrc->_type = type;
749   if ( type == SMESH::ALL && ids.length() > 0 )
750     idSrc->_type = myMesh_i->GetElementType( ids[0], true );
751
752   SMESH::SMESH_IDSource_var anIDSourceVar = idSrc->_this();
753
754   return anIDSourceVar._retn();
755 }
756
757 bool SMESH_MeshEditor_i::IsTemporaryIDSource( SMESH::SMESH_IDSource_ptr& idSource )
758 {
759   return SMESH::DownCast<SMESH_MeshEditor_i::_IDSource*>( idSource );
760 }
761
762 CORBA::Long* SMESH_MeshEditor_i::GetTemporaryIDs( SMESH::SMESH_IDSource_ptr& idSource,
763                                                   int&                       nbIds)
764 {
765   if ( _IDSource* tmpIdSource = SMESH::DownCast<SMESH_MeshEditor_i::_IDSource*>( idSource ))
766   {
767     nbIds = (int) tmpIdSource->_ids.length();
768     return & tmpIdSource->_ids[0];
769   }
770   nbIds = 0;
771   return 0;
772 }
773
774 // void SMESH_MeshEditor_i::deleteAuxIDSources()
775 // {
776 //   std::list< _IDSource* >::iterator idSrcIt = myAuxIDSources.begin();
777 //   for ( ; idSrcIt != myAuxIDSources.end(); ++idSrcIt )
778 //     delete *idSrcIt;
779 //   myAuxIDSources.clear();
780 // }
781
782 //=============================================================================
783 /*!
784  *
785  */
786 //=============================================================================
787
788 CORBA::Boolean
789 SMESH_MeshEditor_i::RemoveElements(const SMESH::long_array & IDsOfElements)
790   throw (SALOME::SALOME_Exception)
791 {
792   SMESH_TRY;
793   initData();
794
795   list< int > IdList;
796
797   for ( CORBA::ULong i = 0; i < IDsOfElements.length(); i++ )
798     IdList.push_back( IDsOfElements[i] );
799
800   // Update Python script
801   TPythonDump() << "isDone = " << this << ".RemoveElements( " << IDsOfElements << " )";
802
803   // Remove Elements
804   bool ret = getEditor().Remove( IdList, false );
805
806   declareMeshModified( /*isReComputeSafe=*/ IDsOfElements.length() == 0 ); // issue 0020693
807   return ret;
808
809   SMESH_CATCH( SMESH::throwCorbaException );
810   return 0;
811 }
812
813 //=============================================================================
814 /*!
815  *
816  */
817 //=============================================================================
818
819 CORBA::Boolean SMESH_MeshEditor_i::RemoveNodes(const SMESH::long_array & IDsOfNodes)
820   throw (SALOME::SALOME_Exception)
821 {
822   SMESH_TRY;
823   initData();
824
825   list< int > IdList;
826   for ( CORBA::ULong i = 0; i < IDsOfNodes.length(); i++)
827     IdList.push_back( IDsOfNodes[i] );
828
829   // Update Python script
830   TPythonDump() << "isDone = " << this << ".RemoveNodes( " << IDsOfNodes << " )";
831
832   bool ret = getEditor().Remove( IdList, true );
833
834   declareMeshModified( /*isReComputeSafe=*/ !ret ); // issue 0020693
835   return ret;
836
837   SMESH_CATCH( SMESH::throwCorbaException );
838   return 0;
839 }
840
841 //=============================================================================
842 /*!
843  *
844  */
845 //=============================================================================
846
847 CORBA::Long SMESH_MeshEditor_i::RemoveOrphanNodes()
848   throw (SALOME::SALOME_Exception)
849 {
850   SMESH_TRY;
851   initData();
852
853   // Update Python script
854   TPythonDump() << "nbRemoved = " << this << ".RemoveOrphanNodes()";
855
856   // Create filter to find all orphan nodes
857   SMESH::Controls::Filter::TIdSequence seq;
858   SMESH::Controls::PredicatePtr predicate( new SMESH::Controls::FreeNodes() );
859   SMESH::Controls::Filter::GetElementsId( getMeshDS(), predicate, seq );
860
861   // remove orphan nodes (if there are any)
862   list< int > IdList( seq.begin(), seq.end() );
863
864   int nbNodesBefore = myMesh->NbNodes();
865   getEditor().Remove( IdList, true );
866   int nbNodesAfter = myMesh->NbNodes();
867
868   declareMeshModified( /*isReComputeSafe=*/ IdList.size() == 0 ); // issue 0020693
869   return nbNodesBefore - nbNodesAfter;
870
871   SMESH_CATCH( SMESH::throwCorbaException );
872   return 0;
873 }
874
875 //=============================================================================
876 /*!
877  * Add a new node.
878  */
879 //=============================================================================
880
881 CORBA::Long SMESH_MeshEditor_i::AddNode(CORBA::Double x,CORBA::Double y, CORBA::Double z)
882   throw (SALOME::SALOME_Exception)
883 {
884   SMESH_TRY;
885   initData();
886
887   const SMDS_MeshNode* N = getMeshDS()->AddNode(x, y, z);
888
889   // Update Python script
890   TPythonDump() << "nodeID = " << this << ".AddNode( "
891                 << TVar( x ) << ", " << TVar( y ) << ", " << TVar( z )<< " )";
892
893   declareMeshModified( /*isReComputeSafe=*/false );
894   return N->GetID();
895
896   SMESH_CATCH( SMESH::throwCorbaException );
897   return 0;
898 }
899
900 //=============================================================================
901 /*!
902  * Create 0D element on the given node.
903  */
904 //=============================================================================
905
906 CORBA::Long SMESH_MeshEditor_i::Add0DElement(CORBA::Long IDOfNode)
907   throw (SALOME::SALOME_Exception)
908 {
909   SMESH_TRY;
910   initData();
911
912   const SMDS_MeshNode* aNode = getMeshDS()->FindNode(IDOfNode);
913   SMDS_MeshElement* elem = getMeshDS()->Add0DElement(aNode);
914
915   // Update Python script
916   TPythonDump() << "elem0d = " << this << ".Add0DElement( " << IDOfNode <<" )";
917
918   declareMeshModified( /*isReComputeSafe=*/false );
919
920   return elem ? elem->GetID() : 0;
921
922   SMESH_CATCH( SMESH::throwCorbaException );
923   return 0;
924 }
925
926 //=============================================================================
927 /*!
928  * Create a ball element on the given node.
929  */
930 //=============================================================================
931
932 CORBA::Long SMESH_MeshEditor_i::AddBall(CORBA::Long IDOfNode, CORBA::Double diameter)
933   throw (SALOME::SALOME_Exception)
934 {
935   SMESH_TRY;
936   initData();
937
938   if ( diameter < std::numeric_limits<double>::min() )
939     THROW_SALOME_CORBA_EXCEPTION("Invalid diameter", SALOME::BAD_PARAM);
940
941   const SMDS_MeshNode* aNode = getMeshDS()->FindNode(IDOfNode);
942   SMDS_MeshElement* elem = getMeshDS()->AddBall(aNode, diameter);
943
944   // Update Python script
945   TPythonDump() << "ballElem = "
946                 << this << ".AddBall( " << IDOfNode << ", " << diameter <<" )";
947
948   declareMeshModified( /*isReComputeSafe=*/false );
949   return elem ? elem->GetID() : 0;
950
951   SMESH_CATCH( SMESH::throwCorbaException );
952   return 0;
953 }
954
955 //=============================================================================
956 /*!
957  * Create an edge, either linear and quadratic (this is determed
958  *  by number of given nodes, two or three)
959  */
960 //=============================================================================
961
962 CORBA::Long SMESH_MeshEditor_i::AddEdge(const SMESH::long_array & IDsOfNodes)
963   throw (SALOME::SALOME_Exception)
964 {
965   SMESH_TRY;
966   initData();
967
968   int NbNodes = IDsOfNodes.length();
969   SMDS_MeshElement* elem = 0;
970   if (NbNodes == 2)
971   {
972     CORBA::Long index1 = IDsOfNodes[0];
973     CORBA::Long index2 = IDsOfNodes[1];
974     elem = getMeshDS()->AddEdge( getMeshDS()->FindNode(index1),
975                                  getMeshDS()->FindNode(index2));
976
977     // Update Python script
978     TPythonDump() << "edge = " << this << ".AddEdge([ "
979                   << index1 << ", " << index2 <<" ])";
980   }
981   if (NbNodes == 3) {
982     CORBA::Long n1 = IDsOfNodes[0];
983     CORBA::Long n2 = IDsOfNodes[1];
984     CORBA::Long n12 = IDsOfNodes[2];
985     elem = getMeshDS()->AddEdge( getMeshDS()->FindNode(n1),
986                                  getMeshDS()->FindNode(n2),
987                                  getMeshDS()->FindNode(n12));
988     // Update Python script
989     TPythonDump() << "edgeID = " << this << ".AddEdge([ "
990                   <<n1<<", "<<n2<<", "<<n12<<" ])";
991   }
992
993   declareMeshModified( /*isReComputeSafe=*/false );
994   return elem ? elem->GetID() : 0;
995
996   SMESH_CATCH( SMESH::throwCorbaException );
997   return 0;
998 }
999
1000 //=============================================================================
1001 /*!
1002  *  AddFace
1003  */
1004 //=============================================================================
1005
1006 CORBA::Long SMESH_MeshEditor_i::AddFace(const SMESH::long_array & IDsOfNodes)
1007   throw (SALOME::SALOME_Exception)
1008 {
1009   SMESH_TRY;
1010   initData();
1011
1012   int NbNodes = IDsOfNodes.length();
1013   if (NbNodes < 3)
1014   {
1015     return 0;
1016   }
1017
1018   std::vector<const SMDS_MeshNode*> nodes (NbNodes);
1019   for (int i = 0; i < NbNodes; i++)
1020     nodes[i] = getMeshDS()->FindNode(IDsOfNodes[i]);
1021
1022   SMDS_MeshElement* elem = 0;
1023   switch (NbNodes) {
1024   case 3: elem = getMeshDS()->AddFace(nodes[0], nodes[1], nodes[2]); break;
1025   case 4: elem = getMeshDS()->AddFace(nodes[0], nodes[1], nodes[2], nodes[3]); break;
1026   case 6: elem = getMeshDS()->AddFace(nodes[0], nodes[1], nodes[2], nodes[3],
1027                                       nodes[4], nodes[5]); break;
1028   case 7: elem = getMeshDS()->AddFace(nodes[0], nodes[1], nodes[2], nodes[3],
1029                                       nodes[4], nodes[5], nodes[6]); break;
1030   case 8: elem = getMeshDS()->AddFace(nodes[0], nodes[1], nodes[2], nodes[3],
1031                                       nodes[4], nodes[5], nodes[6], nodes[7]); break;
1032   case 9: elem = getMeshDS()->AddFace(nodes[0], nodes[1], nodes[2], nodes[3],
1033                                       nodes[4], nodes[5], nodes[6], nodes[7],
1034                                       nodes[8] ); break;
1035   default: elem = getMeshDS()->AddPolygonalFace(nodes);
1036   }
1037
1038   // Update Python script
1039   TPythonDump() << "faceID = " << this << ".AddFace( " << IDsOfNodes << " )";
1040
1041   declareMeshModified( /*isReComputeSafe=*/false );
1042
1043   return elem ? elem->GetID() : 0;
1044
1045   SMESH_CATCH( SMESH::throwCorbaException );
1046   return 0;
1047 }
1048
1049 //=============================================================================
1050 /*!
1051  *  AddPolygonalFace
1052  */
1053 //=============================================================================
1054
1055 CORBA::Long SMESH_MeshEditor_i::AddPolygonalFace (const SMESH::long_array & IDsOfNodes)
1056   throw (SALOME::SALOME_Exception)
1057 {
1058   SMESH_TRY;
1059   initData();
1060
1061   int NbNodes = IDsOfNodes.length();
1062   std::vector<const SMDS_MeshNode*> nodes (NbNodes);
1063   for (int i = 0; i < NbNodes; i++)
1064     if ( ! ( nodes[i] = getMeshDS()->FindNode( IDsOfNodes[i] )))
1065       return 0;
1066
1067   const SMDS_MeshElement* elem = getMeshDS()->AddPolygonalFace(nodes);
1068
1069   // Update Python script
1070   TPythonDump() <<"faceID = "<<this<<".AddPolygonalFace( "<<IDsOfNodes<<" )";
1071
1072   declareMeshModified( /*isReComputeSafe=*/false );
1073   return elem ? elem->GetID() : 0;
1074
1075   SMESH_CATCH( SMESH::throwCorbaException );
1076   return 0;
1077 }
1078
1079 //=============================================================================
1080 /*!
1081  *  AddQuadPolygonalFace
1082  */
1083 //=============================================================================
1084
1085 CORBA::Long SMESH_MeshEditor_i::AddQuadPolygonalFace (const SMESH::long_array & IDsOfNodes)
1086   throw (SALOME::SALOME_Exception)
1087 {
1088   SMESH_TRY;
1089   initData();
1090
1091   int NbNodes = IDsOfNodes.length();
1092   std::vector<const SMDS_MeshNode*> nodes (NbNodes);
1093   for (int i = 0; i < NbNodes; i++)
1094     nodes[i] = getMeshDS()->FindNode(IDsOfNodes[i]);
1095
1096   const SMDS_MeshElement* elem = getMeshDS()->AddQuadPolygonalFace(nodes);
1097
1098   // Update Python script
1099   TPythonDump() <<"faceID = "<<this<<".AddPolygonalFace( "<<IDsOfNodes<<" )";
1100
1101   declareMeshModified( /*isReComputeSafe=*/false );
1102   return elem ? elem->GetID() : 0;
1103
1104   SMESH_CATCH( SMESH::throwCorbaException );
1105   return 0;
1106 }
1107
1108 //=============================================================================
1109 /*!
1110  * Create volume, either linear and quadratic (this is determed
1111  *  by number of given nodes)
1112  */
1113 //=============================================================================
1114
1115 CORBA::Long SMESH_MeshEditor_i::AddVolume(const SMESH::long_array & IDsOfNodes)
1116   throw (SALOME::SALOME_Exception)
1117 {
1118   SMESH_TRY;
1119   initData();
1120
1121   int NbNodes = IDsOfNodes.length();
1122   vector< const SMDS_MeshNode*> n(NbNodes);
1123   for(int i=0;i<NbNodes;i++)
1124     n[i]= getMeshDS()->FindNode(IDsOfNodes[i]);
1125
1126   SMDS_MeshElement* elem = 0;
1127   switch(NbNodes)
1128   {
1129   case 4 :elem = getMeshDS()->AddVolume(n[0],n[1],n[2],n[3]); break;
1130   case 5 :elem = getMeshDS()->AddVolume(n[0],n[1],n[2],n[3],n[4]); break;
1131   case 6 :elem = getMeshDS()->AddVolume(n[0],n[1],n[2],n[3],n[4],n[5]); break;
1132   case 8 :elem = getMeshDS()->AddVolume(n[0],n[1],n[2],n[3],n[4],n[5],n[6],n[7]); break;
1133   case 10:elem = getMeshDS()->AddVolume(n[0],n[1],n[2],n[3],n[4],n[5],
1134                                         n[6],n[7],n[8],n[9]);
1135     break;
1136   case 12:elem = getMeshDS()->AddVolume(n[0],n[1],n[2],n[3],n[4],n[5],
1137                                         n[6],n[7],n[8],n[9],n[10],n[11]);
1138     break;
1139   case 13:elem = getMeshDS()->AddVolume(n[0],n[1],n[2],n[3],n[4],n[5],n[6],
1140                                         n[7],n[8],n[9],n[10],n[11],n[12]);
1141     break;
1142   case 15:elem = getMeshDS()->AddVolume(n[0],n[1],n[2],n[3],n[4],n[5],n[6],n[7],n[8],
1143                                         n[9],n[10],n[11],n[12],n[13],n[14]);
1144     break;
1145   case 20:elem = getMeshDS()->AddVolume(n[0],n[1],n[2],n[3],n[4],n[5],n[6],n[7],
1146                                         n[8],n[9],n[10],n[11],n[12],n[13],n[14],
1147                                         n[15],n[16],n[17],n[18],n[19]);
1148     break;
1149   case 27:elem = getMeshDS()->AddVolume(n[0],n[1],n[2],n[3],n[4],n[5],n[6],n[7],
1150                                         n[8],n[9],n[10],n[11],n[12],n[13],n[14],
1151                                         n[15],n[16],n[17],n[18],n[19],
1152                                         n[20],n[21],n[22],n[23],n[24],n[25],n[26]);
1153     break;
1154   }
1155
1156   // Update Python script
1157   TPythonDump() << "volID = " << this << ".AddVolume( " << IDsOfNodes << " )";
1158
1159   declareMeshModified( /*isReComputeSafe=*/false );
1160   return elem ? elem->GetID() : 0;
1161
1162   SMESH_CATCH( SMESH::throwCorbaException );
1163   return 0;
1164 }
1165
1166 //=============================================================================
1167 /*!
1168  *  AddPolyhedralVolume
1169  */
1170 //=============================================================================
1171 CORBA::Long SMESH_MeshEditor_i::AddPolyhedralVolume (const SMESH::long_array & IDsOfNodes,
1172                                                      const SMESH::long_array & Quantities)
1173   throw (SALOME::SALOME_Exception)
1174 {
1175   SMESH_TRY;
1176   initData();
1177
1178   int NbNodes = IDsOfNodes.length();
1179   std::vector<const SMDS_MeshNode*> n (NbNodes);
1180   for (int i = 0; i < NbNodes; i++)
1181     {
1182       const SMDS_MeshNode* aNode = getMeshDS()->FindNode(IDsOfNodes[i]);
1183       if (!aNode) return 0;
1184       n[i] = aNode;
1185     }
1186
1187   int NbFaces = Quantities.length();
1188   std::vector<int> q (NbFaces);
1189   for (int j = 0; j < NbFaces; j++)
1190     q[j] = Quantities[j];
1191
1192   const SMDS_MeshElement* elem = getMeshDS()->AddPolyhedralVolume(n, q);
1193
1194   // Update Python script
1195   TPythonDump() << "volID = " << this << ".AddPolyhedralVolume( "
1196                 << IDsOfNodes << ", " << Quantities << " )";
1197
1198   declareMeshModified( /*isReComputeSafe=*/false );
1199   return elem ? elem->GetID() : 0;
1200
1201   SMESH_CATCH( SMESH::throwCorbaException );
1202   return 0;
1203 }
1204
1205 //=============================================================================
1206 /*!
1207  *  AddPolyhedralVolumeByFaces
1208  */
1209 //=============================================================================
1210
1211 CORBA::Long SMESH_MeshEditor_i::AddPolyhedralVolumeByFaces (const SMESH::long_array & IdsOfFaces)
1212   throw (SALOME::SALOME_Exception)
1213 {
1214   SMESH_TRY;
1215   initData();
1216
1217   int NbFaces = IdsOfFaces.length();
1218   std::vector<const SMDS_MeshNode*> poly_nodes;
1219   std::vector<int> quantities (NbFaces);
1220
1221   for (int i = 0; i < NbFaces; i++) {
1222     const SMDS_MeshElement* aFace = getMeshDS()->FindElement(IdsOfFaces[i]);
1223     quantities[i] = aFace->NbNodes();
1224
1225     SMDS_ElemIteratorPtr It = aFace->nodesIterator();
1226     while (It->more()) {
1227       poly_nodes.push_back(static_cast<const SMDS_MeshNode *>(It->next()));
1228     }
1229   }
1230
1231   const SMDS_MeshElement* elem = getMeshDS()->AddPolyhedralVolume(poly_nodes, quantities);
1232
1233   // Update Python script
1234   TPythonDump() << "volID = " << this << ".AddPolyhedralVolumeByFaces( "
1235                 << IdsOfFaces << " )";
1236
1237   declareMeshModified( /*isReComputeSafe=*/false );
1238   return elem ? elem->GetID() : 0;
1239
1240   SMESH_CATCH( SMESH::throwCorbaException );
1241   return 0;
1242 }
1243
1244 //=============================================================================
1245 //
1246 // \brief Create 0D elements on all nodes of the given object except those 
1247 //        nodes on which a 0D element already exists.
1248 //  \param theObject object on whose nodes 0D elements will be created.
1249 //  \param theGroupName optional name of a group to add 0D elements created
1250 //         and/or found on nodes of \a theObject.
1251 //  \return an object (a new group or a temporary SMESH_IDSource) holding
1252 //          ids of new and/or found 0D elements.
1253 //
1254 //=============================================================================
1255
1256 SMESH::SMESH_IDSource_ptr
1257 SMESH_MeshEditor_i::Create0DElementsOnAllNodes(SMESH::SMESH_IDSource_ptr theObject,
1258                                                const char*               theGroupName)
1259   throw (SALOME::SALOME_Exception)
1260 {
1261   SMESH_TRY;
1262   initData();
1263
1264   SMESH::SMESH_IDSource_var result;
1265   TPythonDump pyDump;
1266
1267   TIDSortedElemSet elements, elems0D;
1268   if ( idSourceToSet( theObject, getMeshDS(), elements, SMDSAbs_All, /*emptyIfIsMesh=*/1))
1269     getEditor().Create0DElementsOnAllNodes( elements, elems0D );
1270
1271   SMESH::long_array_var newElems = new SMESH::long_array;
1272   newElems->length( elems0D.size() );
1273   TIDSortedElemSet::iterator eIt = elems0D.begin();
1274   for ( size_t i = 0; i < elems0D.size(); ++i, ++eIt )
1275     newElems[ i ] = (*eIt)->GetID();
1276
1277   SMESH::SMESH_GroupBase_var groupToFill;
1278   if ( theGroupName && strlen( theGroupName ))
1279   {
1280     // Get existing group named theGroupName
1281     SMESH::ListOfGroups_var groups = myMesh_i->GetGroups();
1282     for (int i = 0, nbGroups = groups->length(); i < nbGroups; i++ ) {
1283       SMESH::SMESH_GroupBase_var group = groups[i];
1284       if ( !group->_is_nil() ) {
1285         CORBA::String_var name = group->GetName();
1286         if ( strcmp( name.in(), theGroupName ) == 0 && group->GetType() == SMESH::ELEM0D ) {
1287           groupToFill = group;
1288           break;
1289         }
1290       }
1291     }
1292     if ( groupToFill->_is_nil() )
1293       groupToFill = myMesh_i->CreateGroup( SMESH::ELEM0D, theGroupName );
1294     else if ( !SMESH::DownCast< SMESH_Group_i* > ( groupToFill ))
1295       groupToFill = myMesh_i->ConvertToStandalone( groupToFill );
1296   }
1297
1298   if ( SMESH_Group_i* group_i = SMESH::DownCast< SMESH_Group_i* > ( groupToFill ))
1299   {
1300     group_i->Add( newElems );
1301     result = SMESH::SMESH_IDSource::_narrow( groupToFill );
1302     pyDump << groupToFill;
1303   }
1304   else
1305   {
1306     result = MakeIDSource( newElems, SMESH::ELEM0D );
1307     pyDump << "elem0DIDs";
1308   }
1309
1310   pyDump << " = " << this << ".Create0DElementsOnAllNodes( "
1311          << theObject << ", '" << theGroupName << "' )";
1312
1313   return result._retn();
1314
1315   SMESH_CATCH( SMESH::throwCorbaException );
1316   return 0;
1317 }
1318
1319 //=============================================================================
1320 /*!
1321  * \brief Bind a node to a vertex
1322  * \param NodeID - node ID
1323  * \param VertexID - vertex ID available through GEOM_Object.GetSubShapeIndices()[0]
1324  * \retval boolean - false if NodeID or VertexID is invalid
1325  */
1326 //=============================================================================
1327
1328 void SMESH_MeshEditor_i::SetNodeOnVertex(CORBA::Long NodeID, CORBA::Long VertexID)
1329   throw (SALOME::SALOME_Exception)
1330 {
1331   SMESH_TRY;
1332
1333   SMESHDS_Mesh * mesh = getMeshDS();
1334   SMDS_MeshNode* node = const_cast<SMDS_MeshNode*>( mesh->FindNode(NodeID) );
1335   if ( !node )
1336     THROW_SALOME_CORBA_EXCEPTION("Invalid NodeID", SALOME::BAD_PARAM);
1337
1338   if ( mesh->MaxShapeIndex() < VertexID )
1339     THROW_SALOME_CORBA_EXCEPTION("Invalid VertexID", SALOME::BAD_PARAM);
1340
1341   TopoDS_Shape shape = mesh->IndexToShape( VertexID );
1342   if ( shape.ShapeType() != TopAbs_VERTEX )
1343     THROW_SALOME_CORBA_EXCEPTION("Invalid VertexID", SALOME::BAD_PARAM);
1344
1345   mesh->SetNodeOnVertex( node, VertexID );
1346
1347   myMesh->SetIsModified( true );
1348
1349   SMESH_CATCH( SMESH::throwCorbaException );
1350 }
1351
1352 //=============================================================================
1353 /*!
1354  * \brief Store node position on an edge
1355  * \param NodeID - node ID
1356  * \param EdgeID - edge ID available through GEOM_Object.GetSubShapeIndices()[0]
1357  * \param paramOnEdge - parameter on edge where the node is located
1358  * \retval boolean - false if any parameter is invalid
1359  */
1360 //=============================================================================
1361
1362 void SMESH_MeshEditor_i::SetNodeOnEdge(CORBA::Long NodeID, CORBA::Long EdgeID,
1363                                        CORBA::Double paramOnEdge)
1364   throw (SALOME::SALOME_Exception)
1365 {
1366   SMESH_TRY;
1367
1368   SMESHDS_Mesh * mesh = getMeshDS();
1369   SMDS_MeshNode* node = const_cast<SMDS_MeshNode*>( mesh->FindNode(NodeID) );
1370   if ( !node )
1371     THROW_SALOME_CORBA_EXCEPTION("Invalid NodeID", SALOME::BAD_PARAM);
1372
1373   if ( mesh->MaxShapeIndex() < EdgeID )
1374     THROW_SALOME_CORBA_EXCEPTION("Invalid EdgeID", SALOME::BAD_PARAM);
1375
1376   TopoDS_Shape shape = mesh->IndexToShape( EdgeID );
1377   if ( shape.ShapeType() != TopAbs_EDGE )
1378     THROW_SALOME_CORBA_EXCEPTION("Invalid EdgeID", SALOME::BAD_PARAM);
1379
1380   Standard_Real f,l;
1381   BRep_Tool::Range( TopoDS::Edge( shape ), f,l);
1382   if ( paramOnEdge < f || paramOnEdge > l )
1383     THROW_SALOME_CORBA_EXCEPTION("Invalid paramOnEdge", SALOME::BAD_PARAM);
1384
1385   mesh->SetNodeOnEdge( node, EdgeID, paramOnEdge );
1386
1387   myMesh->SetIsModified( true );
1388
1389   SMESH_CATCH( SMESH::throwCorbaException );
1390 }
1391
1392 //=============================================================================
1393 /*!
1394  * \brief Store node position on a face
1395  * \param NodeID - node ID
1396  * \param FaceID - face ID available through GEOM_Object.GetSubShapeIndices()[0]
1397  * \param u - U parameter on face where the node is located
1398  * \param v - V parameter on face where the node is located
1399  * \retval boolean - false if any parameter is invalid
1400  */
1401 //=============================================================================
1402
1403 void SMESH_MeshEditor_i::SetNodeOnFace(CORBA::Long NodeID, CORBA::Long FaceID,
1404                                        CORBA::Double u, CORBA::Double v)
1405   throw (SALOME::SALOME_Exception)
1406 {
1407   SMESH_TRY;
1408   SMESHDS_Mesh * mesh = getMeshDS();
1409   SMDS_MeshNode* node = const_cast<SMDS_MeshNode*>( mesh->FindNode(NodeID) );
1410   if ( !node )
1411     THROW_SALOME_CORBA_EXCEPTION("Invalid NodeID", SALOME::BAD_PARAM);
1412
1413   if ( mesh->MaxShapeIndex() < FaceID )
1414     THROW_SALOME_CORBA_EXCEPTION("Invalid FaceID", SALOME::BAD_PARAM);
1415
1416   TopoDS_Shape shape = mesh->IndexToShape( FaceID );
1417   if ( shape.ShapeType() != TopAbs_FACE )
1418     THROW_SALOME_CORBA_EXCEPTION("Invalid FaceID", SALOME::BAD_PARAM);
1419
1420   BRepAdaptor_Surface surf( TopoDS::Face( shape ));
1421   bool isOut = ( u < surf.FirstUParameter() ||
1422                  u > surf.LastUParameter()  ||
1423                  v < surf.FirstVParameter() ||
1424                  v > surf.LastVParameter() );
1425
1426   if ( isOut ) {
1427 #ifdef _DEBUG_
1428     MESSAGE ( "FACE " << FaceID << " (" << u << "," << v << ") out of "
1429               << " u( " <<  surf.FirstUParameter()
1430               << "," <<  surf.LastUParameter()
1431               << ") v( " <<  surf.FirstVParameter()
1432               << "," <<  surf.LastVParameter() << ")" );
1433 #endif
1434     THROW_SALOME_CORBA_EXCEPTION("Invalid UV", SALOME::BAD_PARAM);
1435   }
1436
1437   mesh->SetNodeOnFace( node, FaceID, u, v );
1438   myMesh->SetIsModified( true );
1439
1440   SMESH_CATCH( SMESH::throwCorbaException );
1441 }
1442
1443 //=============================================================================
1444 /*!
1445  * \brief Bind a node to a solid
1446  * \param NodeID - node ID
1447  * \param SolidID - vertex ID available through GEOM_Object.GetSubShapeIndices()[0]
1448  * \retval boolean - false if NodeID or SolidID is invalid
1449  */
1450 //=============================================================================
1451
1452 void SMESH_MeshEditor_i::SetNodeInVolume(CORBA::Long NodeID, CORBA::Long SolidID)
1453   throw (SALOME::SALOME_Exception)
1454 {
1455   SMESH_TRY;
1456   SMESHDS_Mesh * mesh = getMeshDS();
1457   SMDS_MeshNode* node = const_cast<SMDS_MeshNode*>( mesh->FindNode(NodeID) );
1458   if ( !node )
1459     THROW_SALOME_CORBA_EXCEPTION("Invalid NodeID", SALOME::BAD_PARAM);
1460
1461   if ( mesh->MaxShapeIndex() < SolidID )
1462     THROW_SALOME_CORBA_EXCEPTION("Invalid SolidID", SALOME::BAD_PARAM);
1463
1464   TopoDS_Shape shape = mesh->IndexToShape( SolidID );
1465   if ( shape.ShapeType() != TopAbs_SOLID &&
1466        shape.ShapeType() != TopAbs_SHELL)
1467     THROW_SALOME_CORBA_EXCEPTION("Invalid SolidID", SALOME::BAD_PARAM);
1468
1469   mesh->SetNodeInVolume( node, SolidID );
1470
1471   SMESH_CATCH( SMESH::throwCorbaException );
1472 }
1473
1474 //=============================================================================
1475 /*!
1476  * \brief Bind an element to a shape
1477  * \param ElementID - element ID
1478  * \param ShapeID - shape ID available through GEOM_Object.GetSubShapeIndices()[0]
1479  */
1480 //=============================================================================
1481
1482 void SMESH_MeshEditor_i::SetMeshElementOnShape(CORBA::Long ElementID,
1483                                                CORBA::Long ShapeID)
1484   throw (SALOME::SALOME_Exception)
1485 {
1486   SMESH_TRY;
1487   SMESHDS_Mesh * mesh = getMeshDS();
1488   SMDS_MeshElement* elem = const_cast<SMDS_MeshElement*>(mesh->FindElement(ElementID));
1489   if ( !elem )
1490     THROW_SALOME_CORBA_EXCEPTION("Invalid ElementID", SALOME::BAD_PARAM);
1491
1492   if ( mesh->MaxShapeIndex() < ShapeID || ShapeID < 1 )
1493     THROW_SALOME_CORBA_EXCEPTION("Invalid ShapeID", SALOME::BAD_PARAM);
1494
1495   TopoDS_Shape shape = mesh->IndexToShape( ShapeID );
1496   if ( shape.ShapeType() != TopAbs_EDGE &&
1497        shape.ShapeType() != TopAbs_FACE &&
1498        shape.ShapeType() != TopAbs_SOLID &&
1499        shape.ShapeType() != TopAbs_SHELL )
1500     THROW_SALOME_CORBA_EXCEPTION("Invalid shape type", SALOME::BAD_PARAM);
1501
1502   mesh->SetMeshElementOnShape( elem, ShapeID );
1503
1504   myMesh->SetIsModified( true );
1505
1506   SMESH_CATCH( SMESH::throwCorbaException );
1507 }
1508
1509 //=============================================================================
1510 /*!
1511  *
1512  */
1513 //=============================================================================
1514
1515 CORBA::Boolean SMESH_MeshEditor_i::InverseDiag(CORBA::Long NodeID1,
1516                                                CORBA::Long NodeID2)
1517   throw (SALOME::SALOME_Exception)
1518 {
1519   SMESH_TRY;
1520   initData();
1521
1522   const SMDS_MeshNode * n1 = getMeshDS()->FindNode( NodeID1 );
1523   const SMDS_MeshNode * n2 = getMeshDS()->FindNode( NodeID2 );
1524   if ( !n1 || !n2 )
1525     return false;
1526
1527   // Update Python script
1528   TPythonDump() << "isDone = " << this << ".InverseDiag( "
1529                 << NodeID1 << ", " << NodeID2 << " )";
1530
1531   int ret =  getEditor().InverseDiag ( n1, n2 );
1532
1533   declareMeshModified( /*isReComputeSafe=*/false );
1534   return ret;
1535
1536   SMESH_CATCH( SMESH::throwCorbaException );
1537   return 0;
1538 }
1539
1540 //=============================================================================
1541 /*!
1542  *
1543  */
1544 //=============================================================================
1545
1546 CORBA::Boolean SMESH_MeshEditor_i::DeleteDiag(CORBA::Long NodeID1,
1547                                               CORBA::Long NodeID2)
1548   throw (SALOME::SALOME_Exception)
1549 {
1550   SMESH_TRY;
1551   initData();
1552
1553   const SMDS_MeshNode * n1 = getMeshDS()->FindNode( NodeID1 );
1554   const SMDS_MeshNode * n2 = getMeshDS()->FindNode( NodeID2 );
1555   if ( !n1 || !n2 )
1556     return false;
1557
1558   // Update Python script
1559   TPythonDump() << "isDone = " << this << ".DeleteDiag( "
1560                 << NodeID1 << ", " << NodeID2 <<  " )";
1561
1562
1563   bool stat = getEditor().DeleteDiag ( n1, n2 );
1564
1565   declareMeshModified( /*isReComputeSafe=*/!stat );
1566
1567   return stat;
1568
1569   SMESH_CATCH( SMESH::throwCorbaException );
1570   return 0;
1571 }
1572
1573 //=============================================================================
1574 /*!
1575  *
1576  */
1577 //=============================================================================
1578
1579 CORBA::Boolean SMESH_MeshEditor_i::Reorient(const SMESH::long_array & IDsOfElements)
1580   throw (SALOME::SALOME_Exception)
1581 {
1582   SMESH_TRY;
1583   initData();
1584
1585   for ( CORBA::ULong i = 0; i < IDsOfElements.length(); i++ )
1586   {
1587     CORBA::Long index = IDsOfElements[i];
1588     const SMDS_MeshElement * elem = getMeshDS()->FindElement(index);
1589     if ( elem )
1590       getEditor().Reorient( elem );
1591   }
1592   // Update Python script
1593   TPythonDump() << "isDone = " << this << ".Reorient( " << IDsOfElements << " )";
1594
1595   declareMeshModified( /*isReComputeSafe=*/ IDsOfElements.length() == 0 );
1596   return true;
1597
1598   SMESH_CATCH( SMESH::throwCorbaException );
1599   return 0;
1600 }
1601
1602 //=============================================================================
1603 /*!
1604  *
1605  */
1606 //=============================================================================
1607
1608 CORBA::Boolean SMESH_MeshEditor_i::ReorientObject(SMESH::SMESH_IDSource_ptr theObject)
1609   throw (SALOME::SALOME_Exception)
1610 {
1611   SMESH_TRY;
1612   initData();
1613
1614   TPythonDump aTPythonDump; // suppress dump in Reorient()
1615
1616   prepareIdSource( theObject );
1617
1618   SMESH::long_array_var anElementsId = theObject->GetIDs();
1619   CORBA::Boolean isDone = Reorient(anElementsId);
1620
1621   // Update Python script
1622   aTPythonDump << "isDone = " << this << ".ReorientObject( " << theObject << " )";
1623
1624   declareMeshModified( /*isReComputeSafe=*/ anElementsId->length() == 0 );
1625   return isDone;
1626
1627   SMESH_CATCH( SMESH::throwCorbaException );
1628   return 0;
1629 }
1630
1631 //=======================================================================
1632 //function : Reorient2D
1633 //purpose  : Reorient faces contained in \a the2Dgroup.
1634 //           the2Dgroup   - the mesh or its part to reorient
1635 //           theDirection - desired direction of normal of \a theFace
1636 //           theFace      - ID of face whose orientation is checked.
1637 //           It can be < 1 then \a thePoint is used to find a face.
1638 //           thePoint     - is used to find a face if \a theFace < 1.
1639 //           return number of reoriented elements.
1640 //=======================================================================
1641
1642 CORBA::Long SMESH_MeshEditor_i::Reorient2D(SMESH::SMESH_IDSource_ptr the2Dgroup,
1643                                            const SMESH::DirStruct&   theDirection,
1644                                            CORBA::Long               theFace,
1645                                            const SMESH::PointStruct& thePoint)
1646   throw (SALOME::SALOME_Exception)
1647 {
1648   SMESH_TRY;
1649   initData(/*deleteSearchers=*/false);
1650
1651   TIDSortedElemSet elements;
1652   IDSource_Error error;
1653   idSourceToSet( the2Dgroup, getMeshDS(), elements, SMDSAbs_Face, /*emptyIfIsMesh=*/1, &error );
1654   if ( error == IDSource_EMPTY )
1655     return 0;
1656   if ( error == IDSource_INVALID )
1657     THROW_SALOME_CORBA_EXCEPTION("No faces in given group", SALOME::BAD_PARAM);
1658
1659
1660   const SMDS_MeshElement* face = 0;
1661   if ( theFace > 0 )
1662   {
1663     face = getMeshDS()->FindElement( theFace );
1664     if ( !face )
1665       THROW_SALOME_CORBA_EXCEPTION("Inexistent face given", SALOME::BAD_PARAM);
1666     if ( face->GetType() != SMDSAbs_Face )
1667       THROW_SALOME_CORBA_EXCEPTION("Wrong element type", SALOME::BAD_PARAM);
1668   }
1669   else
1670   {
1671     // create theElementSearcher if needed
1672     theSearchersDeleter.Set( myMesh, getPartIOR( the2Dgroup, SMESH::FACE ));
1673     if ( !theElementSearcher )
1674     {
1675       if ( elements.empty() ) // search in the whole mesh
1676       {
1677         if ( myMesh->NbFaces() == 0 )
1678           THROW_SALOME_CORBA_EXCEPTION("No faces in the mesh", SALOME::BAD_PARAM);
1679
1680         theElementSearcher = SMESH_MeshAlgos::GetElementSearcher( *getMeshDS() );
1681       }
1682       else
1683       {
1684         typedef SMDS_SetIterator<const SMDS_MeshElement*, TIDSortedElemSet::const_iterator > TIter;
1685         SMDS_ElemIteratorPtr elemsIt( new TIter( elements.begin(), elements.end() ));
1686
1687         theElementSearcher = SMESH_MeshAlgos::GetElementSearcher( *getMeshDS(), elemsIt);
1688       }
1689     }
1690     // find a face
1691     gp_Pnt p( thePoint.x, thePoint.y, thePoint.z );
1692     face = theElementSearcher->FindClosestTo( p, SMDSAbs_Face );
1693
1694     if ( !face )
1695       THROW_SALOME_CORBA_EXCEPTION("No face found by point", SALOME::INTERNAL_ERROR );
1696     if ( !elements.empty() && !elements.count( face ))
1697       THROW_SALOME_CORBA_EXCEPTION("Found face is not in the group", SALOME::BAD_PARAM );
1698   }
1699
1700   const SMESH::PointStruct * P = &theDirection.PS;
1701   gp_Vec dirVec( P->x, P->y, P->z );
1702   if ( dirVec.Magnitude() < std::numeric_limits< double >::min() )
1703     THROW_SALOME_CORBA_EXCEPTION("Zero size vector", SALOME::BAD_PARAM);
1704
1705   int nbReori = getEditor().Reorient2D( elements, dirVec, face );
1706
1707   if ( nbReori ) {
1708     declareMeshModified( /*isReComputeSafe=*/false );
1709   }
1710   TPythonDump() << this << ".Reorient2D( "
1711                 << the2Dgroup << ", "
1712                 << theDirection << ", "
1713                 << theFace << ", "
1714                 << thePoint << " )";
1715
1716   return nbReori;
1717
1718   SMESH_CATCH( SMESH::throwCorbaException );
1719   return 0;
1720 }
1721
1722 //=======================================================================
1723 //function : Reorient2DBy3D
1724 //purpose  : Reorient faces basing on orientation of adjacent volumes.
1725 //=======================================================================
1726
1727 CORBA::Long SMESH_MeshEditor_i::Reorient2DBy3D(const SMESH::ListOfIDSources& faceGroups,
1728                                                SMESH::SMESH_IDSource_ptr     volumeGroup,
1729                                                CORBA::Boolean                outsideNormal)
1730   throw (SALOME::SALOME_Exception)
1731 {
1732   SMESH_TRY;
1733   initData();
1734
1735   TIDSortedElemSet volumes;
1736   IDSource_Error volsError;
1737   idSourceToSet( volumeGroup, getMeshDS(), volumes, SMDSAbs_Volume, /*emptyIfMesh=*/1, &volsError);
1738
1739   int nbReori = 0;
1740   for ( size_t i = 0; i < faceGroups.length(); ++i )
1741   {
1742     SMESH::SMESH_IDSource_ptr faceGrp = faceGroups[i].in();
1743
1744     TIDSortedElemSet faces;
1745     IDSource_Error error;
1746     idSourceToSet( faceGrp, getMeshDS(), faces, SMDSAbs_Face, /*emptyIfIsMesh=*/1, &error );
1747     if ( error == IDSource_INVALID && faceGroups.length() == 1 )
1748       THROW_SALOME_CORBA_EXCEPTION("No faces in a given object", SALOME::BAD_PARAM);
1749     if ( error == IDSource_OK && volsError != IDSource_OK )
1750       THROW_SALOME_CORBA_EXCEPTION("No volumes in a given object", SALOME::BAD_PARAM);
1751
1752     nbReori += getEditor().Reorient2DBy3D( faces, volumes, outsideNormal );
1753
1754     if ( error != IDSource_EMPTY && faces.empty() ) // all faces in the mesh treated
1755       break;
1756   }
1757
1758   if ( nbReori ) {
1759     declareMeshModified( /*isReComputeSafe=*/false );
1760   }
1761   TPythonDump() << this << ".Reorient2DBy3D( "
1762                 << faceGroups << ", "
1763                 << volumeGroup << ", "
1764                 << outsideNormal << " )";
1765
1766   return nbReori;
1767
1768   SMESH_CATCH( SMESH::throwCorbaException );
1769   return 0;
1770 }
1771
1772 //=============================================================================
1773 /*!
1774  * \brief Fuse neighbour triangles into quadrangles.
1775  */
1776 //=============================================================================
1777
1778 CORBA::Boolean SMESH_MeshEditor_i::TriToQuad (const SMESH::long_array &   IDsOfElements,
1779                                               SMESH::NumericalFunctor_ptr Criterion,
1780                                               CORBA::Double               MaxAngle)
1781   throw (SALOME::SALOME_Exception)
1782 {
1783   SMESH_TRY;
1784   initData();
1785
1786   SMESHDS_Mesh* aMesh = getMeshDS();
1787   TIDSortedElemSet faces,copyFaces;
1788   SMDS_MeshElement::GeomFilter triaFilter(SMDSGeom_TRIANGLE);
1789   arrayToSet(IDsOfElements, aMesh, faces, SMDSAbs_Face, & triaFilter);
1790   TIDSortedElemSet* workElements = & faces;
1791
1792   if ( myIsPreviewMode ) {
1793     SMDSAbs_ElementType select =  SMDSAbs_Face;
1794     getPreviewMesh( SMDSAbs_Face )->Copy( faces, copyFaces, select );
1795     workElements = & copyFaces;
1796   }
1797
1798   SMESH::NumericalFunctor_i* aNumericalFunctor =
1799     dynamic_cast<SMESH::NumericalFunctor_i*>( SMESH_Gen_i::GetServant( Criterion ).in() );
1800   SMESH::Controls::NumericalFunctorPtr aCrit;
1801   if ( !aNumericalFunctor )
1802     aCrit.reset( new SMESH::Controls::MaxElementLength2D() );
1803   else
1804     aCrit = aNumericalFunctor->GetNumericalFunctor();
1805
1806   if ( !myIsPreviewMode ) {
1807     // Update Python script
1808     TPythonDump() << "isDone = " << this << ".TriToQuad( "
1809                   << IDsOfElements << ", " << aNumericalFunctor << ", " << TVar( MaxAngle ) << " )";
1810   }
1811
1812   bool stat = getEditor().TriToQuad( *workElements, aCrit, MaxAngle );
1813
1814   declareMeshModified( /*isReComputeSafe=*/!stat );
1815   return stat;
1816
1817   SMESH_CATCH( SMESH::throwCorbaException );
1818   return 0;
1819 }
1820
1821 //=============================================================================
1822 /*!
1823  * \brief Fuse neighbour triangles into quadrangles.
1824  */
1825 //=============================================================================
1826
1827 CORBA::Boolean SMESH_MeshEditor_i::TriToQuadObject (SMESH::SMESH_IDSource_ptr   theObject,
1828                                                     SMESH::NumericalFunctor_ptr Criterion,
1829                                                     CORBA::Double               MaxAngle)
1830   throw (SALOME::SALOME_Exception)
1831 {
1832   SMESH_TRY;
1833   initData();
1834
1835   TPythonDump aTPythonDump;  // suppress dump in TriToQuad()
1836
1837   prepareIdSource( theObject );
1838   SMESH::long_array_var anElementsId = theObject->GetIDs();
1839   CORBA::Boolean isDone = TriToQuad(anElementsId, Criterion, MaxAngle);
1840
1841   if ( !myIsPreviewMode ) {
1842     SMESH::NumericalFunctor_i* aNumericalFunctor =
1843       SMESH::DownCast<SMESH::NumericalFunctor_i*>( Criterion );
1844
1845     // Update Python script
1846     aTPythonDump << "isDone = " << this << ".TriToQuadObject("
1847                  << theObject << ", " << aNumericalFunctor << ", " << TVar( MaxAngle ) << " )";
1848   }
1849
1850   return isDone;
1851
1852   SMESH_CATCH( SMESH::throwCorbaException );
1853   return 0;
1854 }
1855
1856 //=============================================================================
1857 /*!
1858  * \brief Split quadrangles into triangles.
1859  */
1860 //=============================================================================
1861
1862 CORBA::Boolean SMESH_MeshEditor_i::QuadToTri (const SMESH::long_array &   IDsOfElements,
1863                                               SMESH::NumericalFunctor_ptr Criterion)
1864   throw (SALOME::SALOME_Exception)
1865 {
1866   SMESH_TRY;
1867   initData();
1868
1869   SMESHDS_Mesh* aMesh = getMeshDS();
1870   TIDSortedElemSet faces;
1871   arrayToSet(IDsOfElements, aMesh, faces, SMDSAbs_Face);
1872
1873   SMESH::NumericalFunctor_i* aNumericalFunctor =
1874     dynamic_cast<SMESH::NumericalFunctor_i*>( SMESH_Gen_i::GetServant( Criterion ).in() );
1875   SMESH::Controls::NumericalFunctorPtr aCrit;
1876   if ( !aNumericalFunctor )
1877     aCrit.reset( new SMESH::Controls::AspectRatio() );
1878   else
1879     aCrit = aNumericalFunctor->GetNumericalFunctor();
1880
1881
1882   // Update Python script
1883   TPythonDump() << "isDone = " << this << ".QuadToTri( " << IDsOfElements << ", " << aNumericalFunctor << " )";
1884
1885   CORBA::Boolean stat = getEditor().QuadToTri( faces, aCrit );
1886
1887   declareMeshModified( /*isReComputeSafe=*/false );
1888   return stat;
1889
1890   SMESH_CATCH( SMESH::throwCorbaException );
1891   return 0;
1892 }
1893
1894 //=============================================================================
1895 /*!
1896  * \brief Split quadrangles into triangles.
1897  */
1898 //=============================================================================
1899
1900 CORBA::Boolean SMESH_MeshEditor_i::QuadToTriObject (SMESH::SMESH_IDSource_ptr   theObject,
1901                                                     SMESH::NumericalFunctor_ptr Criterion)
1902   throw (SALOME::SALOME_Exception)
1903 {
1904   SMESH_TRY;
1905   initData();
1906
1907   TPythonDump aTPythonDump;  // suppress dump in QuadToTri()
1908
1909   prepareIdSource( theObject );
1910   SMESH::long_array_var anElementsId = theObject->GetIDs();
1911   CORBA::Boolean isDone = QuadToTri(anElementsId, Criterion);
1912
1913   SMESH::NumericalFunctor_i* aNumericalFunctor =
1914     SMESH::DownCast<SMESH::NumericalFunctor_i*>( Criterion );
1915
1916   // Update Python script
1917   aTPythonDump << "isDone = " << this << ".QuadToTriObject( " << theObject << ", " << aNumericalFunctor << " )";
1918
1919   declareMeshModified( /*isReComputeSafe=*/false );
1920   return isDone;
1921
1922   SMESH_CATCH( SMESH::throwCorbaException );
1923   return 0;
1924 }
1925
1926 //================================================================================
1927 /*!
1928  * \brief Split each of quadrangles into 4 triangles.
1929  *  \param [in] theObject - theQuads Container of quadrangles to split.
1930  */
1931 //================================================================================
1932
1933 void SMESH_MeshEditor_i::QuadTo4Tri (SMESH::SMESH_IDSource_ptr theObject)
1934   throw (SALOME::SALOME_Exception)
1935 {
1936   SMESH_TRY;
1937   initData();
1938
1939   TIDSortedElemSet faces;
1940   if ( !idSourceToSet( theObject, getMeshDS(), faces, SMDSAbs_Face, /*emptyIfIsMesh=*/true ) &&
1941        faces.empty() )
1942     THROW_SALOME_CORBA_EXCEPTION("No faces given", SALOME::BAD_PARAM);
1943
1944   getEditor().QuadTo4Tri( faces );
1945   TPythonDump() << this << ".QuadTo4Tri( " << theObject << " )";
1946
1947   SMESH_CATCH( SMESH::throwCorbaException );
1948 }
1949
1950 //=============================================================================
1951 /*!
1952  * \brief Split quadrangles into triangles.
1953  */
1954 //=============================================================================
1955
1956 CORBA::Boolean SMESH_MeshEditor_i::SplitQuad (const SMESH::long_array & IDsOfElements,
1957                                               CORBA::Boolean            Diag13)
1958   throw (SALOME::SALOME_Exception)
1959 {
1960   SMESH_TRY;
1961   initData();
1962
1963   SMESHDS_Mesh* aMesh = getMeshDS();
1964   TIDSortedElemSet faces;
1965   arrayToSet(IDsOfElements, aMesh, faces, SMDSAbs_Face);
1966
1967   // Update Python script
1968   TPythonDump() << "isDone = " << this << ".SplitQuad( "
1969                 << IDsOfElements << ", " << Diag13 << " )";
1970
1971   CORBA::Boolean stat = getEditor().QuadToTri( faces, Diag13 );
1972
1973   declareMeshModified( /*isReComputeSafe=*/ !stat );
1974   return stat;
1975
1976   SMESH_CATCH( SMESH::throwCorbaException );
1977   return 0;
1978 }
1979
1980 //=============================================================================
1981 /*!
1982  * \brief Split quadrangles into triangles.
1983  */
1984 //=============================================================================
1985
1986 CORBA::Boolean SMESH_MeshEditor_i::SplitQuadObject (SMESH::SMESH_IDSource_ptr theObject,
1987                                                     CORBA::Boolean            Diag13)
1988   throw (SALOME::SALOME_Exception)
1989 {
1990   SMESH_TRY;
1991   initData();
1992
1993   TPythonDump aTPythonDump;  // suppress dump in SplitQuad()
1994
1995   prepareIdSource( theObject );
1996   SMESH::long_array_var anElementsId = theObject->GetIDs();
1997   CORBA::Boolean isDone = SplitQuad(anElementsId, Diag13);
1998
1999   // Update Python script
2000   aTPythonDump << "isDone = " << this << ".SplitQuadObject( "
2001                << theObject << ", " << Diag13 << " )";
2002
2003   declareMeshModified( /*isReComputeSafe=*/!isDone );
2004   return isDone;
2005
2006   SMESH_CATCH( SMESH::throwCorbaException );
2007   return 0;
2008 }
2009
2010
2011 //=============================================================================
2012 /*!
2013  * Find better splitting of the given quadrangle.
2014  *  \param IDOfQuad  ID of the quadrangle to be splitted.
2015  *  \param Criterion A criterion to choose a diagonal for splitting.
2016  *  \return 1 if 1-3 diagonal is better, 2 if 2-4
2017  *          diagonal is better, 0 if error occurs.
2018  */
2019 //=============================================================================
2020
2021 CORBA::Long SMESH_MeshEditor_i::BestSplit (CORBA::Long                 IDOfQuad,
2022                                            SMESH::NumericalFunctor_ptr Criterion)
2023   throw (SALOME::SALOME_Exception)
2024 {
2025   SMESH_TRY;
2026   initData();
2027
2028   const SMDS_MeshElement* quad = getMeshDS()->FindElement(IDOfQuad);
2029   if (quad && quad->GetType() == SMDSAbs_Face && quad->NbNodes() == 4)
2030   {
2031     SMESH::NumericalFunctor_i* aNumericalFunctor =
2032       dynamic_cast<SMESH::NumericalFunctor_i*>(SMESH_Gen_i::GetServant(Criterion).in());
2033     SMESH::Controls::NumericalFunctorPtr aCrit;
2034     if (aNumericalFunctor)
2035       aCrit = aNumericalFunctor->GetNumericalFunctor();
2036     else
2037       aCrit.reset(new SMESH::Controls::AspectRatio());
2038
2039     int id = getEditor().BestSplit(quad, aCrit);
2040     declareMeshModified( /*isReComputeSafe=*/ id < 1 );
2041     return id;
2042   }
2043
2044   SMESH_CATCH( SMESH::throwCorbaException );
2045   return 0;
2046 }
2047
2048 //================================================================================
2049 /*!
2050  * \brief Split volumic elements into tetrahedrons
2051  */
2052 //================================================================================
2053
2054 void SMESH_MeshEditor_i::SplitVolumesIntoTetra (SMESH::SMESH_IDSource_ptr elems,
2055                                                 CORBA::Short              methodFlags)
2056   throw (SALOME::SALOME_Exception)
2057 {
2058   SMESH_TRY;
2059   initData();
2060
2061   ::SMESH_MeshEditor::TFacetOfElem elemSet;
2062   const int noneFacet = -1;
2063   SMDS_ElemIteratorPtr volIt = myMesh_i->GetElements( elems, SMESH::VOLUME );
2064   while( volIt->more() )
2065     elemSet.insert( elemSet.end(), make_pair( volIt->next(), noneFacet ));
2066
2067   getEditor().SplitVolumes( elemSet, int( methodFlags ));
2068   declareMeshModified( /*isReComputeSafe=*/true ); // it does not influence Compute()
2069
2070   TPythonDump() << this << ".SplitVolumesIntoTetra( "
2071                 << elems << ", " << methodFlags << " )";
2072
2073   SMESH_CATCH( SMESH::throwCorbaException );
2074 }
2075
2076 //================================================================================
2077 /*!
2078  * \brief Split hexahedra into triangular prisms
2079  *  \param elems - elements to split
2080  *  \param facetToSplitNormal - normal used to find a facet of hexahedron
2081  *         to split into triangles
2082  *  \param methodFlags - flags passing splitting method:
2083  *         1 - split the hexahedron into 2 prisms
2084  *         2 - split the hexahedron into 4 prisms
2085  */
2086 //================================================================================
2087
2088 void SMESH_MeshEditor_i::SplitHexahedraIntoPrisms( SMESH::SMESH_IDSource_ptr  elems,
2089                                                    const SMESH::PointStruct & startHexPoint,
2090                                                    const SMESH::DirStruct&    facetToSplitNormal,
2091                                                    CORBA::Short               methodFlags,
2092                                                    CORBA::Boolean             allDomains)
2093   throw (SALOME::SALOME_Exception)
2094 {
2095   SMESH_TRY;
2096   initData();
2097   prepareIdSource( elems );
2098
2099   gp_Ax1 facetNorm( gp_Pnt( startHexPoint.x,
2100                             startHexPoint.y,
2101                             startHexPoint.z ),
2102                     gp_Dir( facetToSplitNormal.PS.x,
2103                             facetToSplitNormal.PS.y,
2104                             facetToSplitNormal.PS.z ));
2105   TIDSortedElemSet elemSet;
2106   SMESH::long_array_var anElementsId = elems->GetIDs();
2107   SMDS_MeshElement::GeomFilter filter( SMDSGeom_HEXA );
2108   arrayToSet( anElementsId, getMeshDS(), elemSet, SMDSAbs_Volume, &filter );
2109
2110   ::SMESH_MeshEditor::TFacetOfElem elemFacets;
2111   while ( !elemSet.empty() )
2112   {
2113     getEditor().GetHexaFacetsToSplit( elemSet, facetNorm, elemFacets );
2114     if ( !allDomains )
2115       break;
2116
2117     ::SMESH_MeshEditor::TFacetOfElem::iterator ef = elemFacets.begin();
2118     for ( ; ef != elemFacets.end(); ++ef )
2119       elemSet.erase( ef->first );
2120   }
2121
2122   if ( methodFlags == 2 )
2123     methodFlags = int( ::SMESH_MeshEditor::HEXA_TO_4_PRISMS );
2124   else
2125     methodFlags = int( ::SMESH_MeshEditor::HEXA_TO_2_PRISMS );
2126
2127   getEditor().SplitVolumes( elemFacets, int( methodFlags ));
2128   declareMeshModified( /*isReComputeSafe=*/true ); // it does not influence Compute()
2129
2130   TPythonDump() << this << ".SplitHexahedraIntoPrisms( "
2131                 << elems << ", "
2132                 << startHexPoint << ", "
2133                 << facetToSplitNormal<< ", "
2134                 << methodFlags<< ", "
2135                 << allDomains << " )";
2136
2137   SMESH_CATCH( SMESH::throwCorbaException );
2138 }
2139
2140 //================================================================================
2141 /*!
2142  * \brief Split bi-quadratic elements into linear ones without creation of additional nodes:
2143  *   - bi-quadratic triangle will be split into 3 linear quadrangles;
2144  *   - bi-quadratic quadrangle will be split into 4 linear quadrangles;
2145  *   - tri-quadratic hexahedron will be split into 8 linear hexahedra.
2146  *   Quadratic elements of lower dimension  adjacent to the split bi-quadratic element
2147  *   will be split in order to keep the mesh conformal.
2148  *  \param elems - elements to split
2149  */
2150 //================================================================================
2151
2152 void SMESH_MeshEditor_i::SplitBiQuadraticIntoLinear(const SMESH::ListOfIDSources& theElems)
2153   throw (SALOME::SALOME_Exception)
2154 {
2155   SMESH_TRY;
2156   initData();
2157
2158   TIDSortedElemSet elemSet;
2159   for ( size_t i = 0; i < theElems.length(); ++i )
2160   {
2161     SMESH::SMESH_IDSource_ptr elems = theElems[i].in();
2162     SMESH::SMESH_Mesh_var      mesh = elems->GetMesh();
2163     if ( mesh->GetId() != myMesh_i->GetId() )
2164       THROW_SALOME_CORBA_EXCEPTION("Wrong mesh of IDSource", SALOME::BAD_PARAM);
2165
2166     idSourceToSet( elems, getMeshDS(), elemSet, SMDSAbs_All );
2167   }
2168   getEditor().SplitBiQuadraticIntoLinear( elemSet );
2169
2170   declareMeshModified( /*isReComputeSafe=*/true ); // it does not influence Compute()
2171
2172   TPythonDump() << this << ".SplitBiQuadraticIntoLinear( "
2173                 << theElems << " )";
2174
2175   SMESH_CATCH( SMESH::throwCorbaException );
2176 }
2177
2178 //=======================================================================
2179 //function : Smooth
2180 //purpose  :
2181 //=======================================================================
2182
2183 CORBA::Boolean
2184 SMESH_MeshEditor_i::Smooth(const SMESH::long_array &              IDsOfElements,
2185                            const SMESH::long_array &              IDsOfFixedNodes,
2186                            CORBA::Long                            MaxNbOfIterations,
2187                            CORBA::Double                          MaxAspectRatio,
2188                            SMESH::SMESH_MeshEditor::Smooth_Method Method)
2189   throw (SALOME::SALOME_Exception)
2190 {
2191   return smooth( IDsOfElements, IDsOfFixedNodes, MaxNbOfIterations,
2192                  MaxAspectRatio, Method, false );
2193 }
2194
2195
2196 //=======================================================================
2197 //function : SmoothParametric
2198 //purpose  :
2199 //=======================================================================
2200
2201 CORBA::Boolean
2202 SMESH_MeshEditor_i::SmoothParametric(const SMESH::long_array &              IDsOfElements,
2203                                      const SMESH::long_array &              IDsOfFixedNodes,
2204                                      CORBA::Long                            MaxNbOfIterations,
2205                                      CORBA::Double                          MaxAspectRatio,
2206                                      SMESH::SMESH_MeshEditor::Smooth_Method Method)
2207   throw (SALOME::SALOME_Exception)
2208 {
2209   return smooth( IDsOfElements, IDsOfFixedNodes, MaxNbOfIterations,
2210                  MaxAspectRatio, Method, true );
2211 }
2212
2213
2214 //=======================================================================
2215 //function : SmoothObject
2216 //purpose  :
2217 //=======================================================================
2218
2219 CORBA::Boolean
2220 SMESH_MeshEditor_i::SmoothObject(SMESH::SMESH_IDSource_ptr              theObject,
2221                                  const SMESH::long_array &              IDsOfFixedNodes,
2222                                  CORBA::Long                            MaxNbOfIterations,
2223                                  CORBA::Double                          MaxAspectRatio,
2224                                  SMESH::SMESH_MeshEditor::Smooth_Method Method)
2225   throw (SALOME::SALOME_Exception)
2226 {
2227   return smoothObject (theObject, IDsOfFixedNodes, MaxNbOfIterations,
2228                        MaxAspectRatio, Method, false);
2229 }
2230
2231
2232 //=======================================================================
2233 //function : SmoothParametricObject
2234 //purpose  :
2235 //=======================================================================
2236
2237 CORBA::Boolean
2238 SMESH_MeshEditor_i::SmoothParametricObject(SMESH::SMESH_IDSource_ptr              theObject,
2239                                            const SMESH::long_array &              IDsOfFixedNodes,
2240                                            CORBA::Long                            MaxNbOfIterations,
2241                                            CORBA::Double                          MaxAspectRatio,
2242                                            SMESH::SMESH_MeshEditor::Smooth_Method Method)
2243   throw (SALOME::SALOME_Exception)
2244 {
2245   return smoothObject (theObject, IDsOfFixedNodes, MaxNbOfIterations,
2246                        MaxAspectRatio, Method, true);
2247 }
2248
2249
2250 //=============================================================================
2251 /*!
2252  *
2253  */
2254 //=============================================================================
2255
2256 CORBA::Boolean
2257 SMESH_MeshEditor_i::smooth(const SMESH::long_array &              IDsOfElements,
2258                            const SMESH::long_array &              IDsOfFixedNodes,
2259                            CORBA::Long                            MaxNbOfIterations,
2260                            CORBA::Double                          MaxAspectRatio,
2261                            SMESH::SMESH_MeshEditor::Smooth_Method Method,
2262                            bool                                   IsParametric)
2263   throw (SALOME::SALOME_Exception)
2264 {
2265   SMESH_TRY;
2266   initData();
2267
2268   SMESHDS_Mesh* aMesh = getMeshDS();
2269
2270   TIDSortedElemSet elements;
2271   arrayToSet(IDsOfElements, aMesh, elements, SMDSAbs_Face);
2272
2273   set<const SMDS_MeshNode*> fixedNodes;
2274   for ( CORBA::ULong i = 0; i < IDsOfFixedNodes.length(); i++) {
2275     CORBA::Long index = IDsOfFixedNodes[i];
2276     const SMDS_MeshNode * node = aMesh->FindNode(index);
2277     if ( node )
2278       fixedNodes.insert( node );
2279   }
2280   ::SMESH_MeshEditor::SmoothMethod method = ::SMESH_MeshEditor::LAPLACIAN;
2281   if ( Method != SMESH::SMESH_MeshEditor::LAPLACIAN_SMOOTH )
2282     method = ::SMESH_MeshEditor::CENTROIDAL;
2283
2284   getEditor().Smooth(elements, fixedNodes, method,
2285                   MaxNbOfIterations, MaxAspectRatio, IsParametric );
2286
2287   declareMeshModified( /*isReComputeSafe=*/true ); // does not prevent re-compute
2288
2289   // Update Python script
2290   TPythonDump() << "isDone = " << this << "."
2291                 << (IsParametric ? "SmoothParametric( " : "Smooth( ")
2292                 << IDsOfElements << ", "     << IDsOfFixedNodes << ", "
2293                 << TVar( MaxNbOfIterations ) << ", " << TVar( MaxAspectRatio ) << ", "
2294                 << "SMESH.SMESH_MeshEditor."
2295                 << ( Method == SMESH::SMESH_MeshEditor::CENTROIDAL_SMOOTH ?
2296                      "CENTROIDAL_SMOOTH )" : "LAPLACIAN_SMOOTH )");
2297
2298   return true;
2299
2300   SMESH_CATCH( SMESH::throwCorbaException );
2301   return 0;
2302 }
2303
2304 //=============================================================================
2305 /*!
2306  *
2307  */
2308 //=============================================================================
2309
2310 CORBA::Boolean
2311 SMESH_MeshEditor_i::smoothObject(SMESH::SMESH_IDSource_ptr              theObject,
2312                                  const SMESH::long_array &              IDsOfFixedNodes,
2313                                  CORBA::Long                            MaxNbOfIterations,
2314                                  CORBA::Double                          MaxAspectRatio,
2315                                  SMESH::SMESH_MeshEditor::Smooth_Method Method,
2316                                  bool                                   IsParametric)
2317   throw (SALOME::SALOME_Exception)
2318 {
2319   SMESH_TRY;
2320   initData();
2321
2322   TPythonDump aTPythonDump;  // suppress dump in smooth()
2323
2324   prepareIdSource( theObject );
2325   SMESH::long_array_var anElementsId = theObject->GetIDs();
2326   CORBA::Boolean isDone = smooth (anElementsId, IDsOfFixedNodes, MaxNbOfIterations,
2327                                   MaxAspectRatio, Method, IsParametric);
2328
2329   // Update Python script
2330   aTPythonDump << "isDone = " << this << "."
2331                << (IsParametric ? "SmoothParametricObject( " : "SmoothObject( ")
2332                << theObject << ", " << IDsOfFixedNodes << ", "
2333                << TVar( MaxNbOfIterations ) << ", " << TVar( MaxAspectRatio ) << ", "
2334                << "SMESH.SMESH_MeshEditor."
2335                << ( Method == SMESH::SMESH_MeshEditor::CENTROIDAL_SMOOTH ?
2336                     "CENTROIDAL_SMOOTH )" : "LAPLACIAN_SMOOTH )");
2337
2338   return isDone;
2339
2340   SMESH_CATCH( SMESH::throwCorbaException );
2341   return 0;
2342 }
2343
2344 //=============================================================================
2345 /*!
2346  *
2347  */
2348 //=============================================================================
2349
2350 void SMESH_MeshEditor_i::RenumberNodes()
2351   throw (SALOME::SALOME_Exception)
2352 {
2353   SMESH_TRY;
2354   // Update Python script
2355   TPythonDump() << this << ".RenumberNodes()";
2356
2357   getMeshDS()->Renumber( true );
2358
2359   SMESH_CATCH( SMESH::throwCorbaException );
2360 }
2361
2362 //=============================================================================
2363 /*!
2364  *
2365  */
2366 //=============================================================================
2367
2368 void SMESH_MeshEditor_i::RenumberElements()
2369   throw (SALOME::SALOME_Exception)
2370 {
2371   SMESH_TRY;
2372   // Update Python script
2373   TPythonDump() << this << ".RenumberElements()";
2374
2375   getMeshDS()->Renumber( false );
2376
2377   SMESH_CATCH( SMESH::throwCorbaException );
2378 }
2379
2380 //=======================================================================
2381 /*!
2382  * \brief Return groups by their IDs
2383  */
2384 //=======================================================================
2385
2386 SMESH::ListOfGroups* SMESH_MeshEditor_i::getGroups(const std::list<int>* groupIDs)
2387   throw (SALOME::SALOME_Exception)
2388 {
2389   SMESH_TRY;
2390   if ( !groupIDs )
2391     return 0;
2392   myMesh_i->CreateGroupServants();
2393   return myMesh_i->GetGroups( *groupIDs );
2394
2395   SMESH_CATCH( SMESH::throwCorbaException );
2396   return 0;
2397 }
2398
2399 //=======================================================================
2400 //function : RotationSweepObjects
2401 //purpose  :
2402 //=======================================================================
2403
2404 SMESH::ListOfGroups*
2405 SMESH_MeshEditor_i::RotationSweepObjects(const SMESH::ListOfIDSources & theNodes,
2406                                          const SMESH::ListOfIDSources & theEdges,
2407                                          const SMESH::ListOfIDSources & theFaces,
2408                                          const SMESH::AxisStruct &      theAxis,
2409                                          CORBA::Double                  theAngleInRadians,
2410                                          CORBA::Long                    theNbOfSteps,
2411                                          CORBA::Double                  theTolerance,
2412                                          const bool                     theMakeGroups)
2413   throw (SALOME::SALOME_Exception)
2414 {
2415   SMESH_TRY;
2416   initData();
2417
2418   TIDSortedElemSet elemsNodes[2];
2419   for ( int i = 0, nb = theNodes.length(); i < nb; ++i ) {
2420     SMDS_ElemIteratorPtr nIt = myMesh_i->GetElements( theNodes[i], SMESH::NODE );
2421     while ( nIt->more() ) elemsNodes[1].insert( nIt->next() );
2422   }
2423   for ( int i = 0, nb = theEdges.length(); i < nb; ++i )
2424     idSourceToSet( theEdges[i], getMeshDS(), elemsNodes[0], SMDSAbs_Edge );
2425   for ( int i = 0, nb = theFaces.length(); i < nb; ++i )
2426     idSourceToSet( theFaces[i], getMeshDS(), elemsNodes[0], SMDSAbs_Face );
2427
2428   TIDSortedElemSet* workElements = & elemsNodes[0], copyElements[2];
2429   bool              makeWalls=true;
2430   if ( myIsPreviewMode )
2431   {
2432     SMDSAbs_ElementType select = SMDSAbs_All, avoid = SMDSAbs_Volume;
2433     TPreviewMesh * tmpMesh = getPreviewMesh();
2434     tmpMesh->Copy( elemsNodes[0], copyElements[0], select, avoid );
2435     tmpMesh->Copy( elemsNodes[1], copyElements[1], select, avoid );
2436     workElements = & copyElements[0];
2437     //makeWalls = false; -- faces are needed for preview
2438   }
2439
2440   TPythonDump aPythonDump; // it is here to prevent dump of getGroups()
2441
2442   gp_Ax1 Ax1 (gp_Pnt( theAxis.x,  theAxis.y,  theAxis.z ),
2443               gp_Vec( theAxis.vx, theAxis.vy, theAxis.vz ));
2444
2445   ::SMESH_MeshEditor::PGroupIDs groupIds =
2446       getEditor().RotationSweep (workElements, Ax1, theAngleInRadians,
2447                                  theNbOfSteps, theTolerance, theMakeGroups, makeWalls);
2448
2449   SMESH::ListOfGroups * aGroups = theMakeGroups ? getGroups( groupIds.get()) : 0;
2450
2451   declareMeshModified( /*isReComputeSafe=*/true ); // does not influence Compute()
2452
2453   if ( !myIsPreviewMode )
2454   {
2455     dumpGroupsList( aPythonDump, aGroups );
2456     aPythonDump << this<< ".RotationSweepObjects( "
2457                 << theNodes                  << ", "
2458                 << theEdges                  << ", "
2459                 << theFaces                  << ", "
2460                 << theAxis                   << ", "
2461                 << TVar( theAngleInRadians ) << ", "
2462                 << TVar( theNbOfSteps      ) << ", "
2463                 << TVar( theTolerance      ) << ", "
2464                 << theMakeGroups             << " )";
2465   }
2466   else
2467   {
2468     getPreviewMesh()->Remove( SMDSAbs_Volume );
2469   }
2470
2471   return aGroups ? aGroups : new SMESH::ListOfGroups;
2472
2473   SMESH_CATCH( SMESH::throwCorbaException );
2474   return 0;
2475 }
2476
2477 namespace MeshEditor_I
2478 {
2479   /*!
2480    * \brief Structure used to pass extrusion parameters to ::SMESH_MeshEditor
2481    */
2482   struct ExtrusionParams : public ::SMESH_MeshEditor::ExtrusParam
2483   {
2484     bool myIsExtrusionByNormal;
2485
2486     static int makeFlags( CORBA::Boolean MakeGroups,
2487                           CORBA::Boolean ByAverageNormal = false,
2488                           CORBA::Boolean UseInputElemsOnly = false,
2489                           CORBA::Long    Flags = 0,
2490                           CORBA::Boolean MakeBoundary = true )
2491     {
2492       if ( MakeGroups       ) Flags |= ::SMESH_MeshEditor::EXTRUSION_FLAG_GROUPS;
2493       if ( ByAverageNormal  ) Flags |= ::SMESH_MeshEditor::EXTRUSION_FLAG_BY_AVG_NORMAL;
2494       if ( UseInputElemsOnly) Flags |= ::SMESH_MeshEditor::EXTRUSION_FLAG_USE_INPUT_ELEMS_ONLY;
2495       if ( MakeBoundary     ) Flags |= ::SMESH_MeshEditor::EXTRUSION_FLAG_BOUNDARY;
2496       return Flags;
2497     }
2498     // standard params
2499     ExtrusionParams(const SMESH::DirStruct &  theDir,
2500                     CORBA::Long               theNbOfSteps,
2501                     CORBA::Boolean            theMakeGroups):
2502       ::SMESH_MeshEditor::ExtrusParam ( gp_Vec( theDir.PS.x,
2503                                                 theDir.PS.y,
2504                                                 theDir.PS.z ),
2505                                         theNbOfSteps,
2506                                         makeFlags( theMakeGroups )),
2507       myIsExtrusionByNormal( false )
2508     {
2509     }
2510     // advanced params
2511     ExtrusionParams(const SMESH::DirStruct &  theDir,
2512                     CORBA::Long               theNbOfSteps,
2513                     CORBA::Boolean            theMakeGroups,
2514                     CORBA::Long               theExtrFlags,
2515                     CORBA::Double             theSewTolerance):
2516       ::SMESH_MeshEditor::ExtrusParam ( gp_Vec( theDir.PS.x,
2517                                                 theDir.PS.y,
2518                                                 theDir.PS.z ),
2519                                         theNbOfSteps,
2520                                         makeFlags( theMakeGroups, false, false,
2521                                                    theExtrFlags, false ),
2522                                         theSewTolerance ),
2523       myIsExtrusionByNormal( false )
2524     {
2525     }
2526     // params for extrusion by normal
2527     ExtrusionParams(CORBA::Double  theStepSize,
2528                     CORBA::Long    theNbOfSteps,
2529                     CORBA::Short   theDim,
2530                     CORBA::Boolean theByAverageNormal,
2531                     CORBA::Boolean theUseInputElemsOnly,
2532                     CORBA::Boolean theMakeGroups ):
2533       ::SMESH_MeshEditor::ExtrusParam ( theStepSize, 
2534                                         theNbOfSteps,
2535                                         makeFlags( theMakeGroups,
2536                                                    theByAverageNormal, theUseInputElemsOnly ),
2537                                         theDim),
2538       myIsExtrusionByNormal( true )
2539     {
2540     }
2541
2542     void SetNoGroups()
2543     {
2544       Flags() &= ~(::SMESH_MeshEditor::EXTRUSION_FLAG_GROUPS);
2545     }
2546   };
2547 }
2548
2549 //=======================================================================
2550 /*!
2551  * \brief Generate dim+1 elements by extrusion of elements along vector
2552  *  \param [in] edges - edges to extrude: a list including groups, sub-meshes or a mesh
2553  *  \param [in] faces - faces to extrude: a list including groups, sub-meshes or a mesh
2554  *  \param [in] nodes - nodes to extrude: a list including groups, sub-meshes or a mesh
2555  *  \param [in] stepVector - vector giving direction and distance of an extrusion step
2556  *  \param [in] nbOfSteps - number of elements to generate from one element
2557  *  \param [in] toMakeGroups - if true, new elements will be included into new groups
2558  *              corresponding to groups the input elements included in.
2559  *  \return ListOfGroups - new groups craeted if \a toMakeGroups is true
2560  */
2561 //=======================================================================
2562
2563 SMESH::ListOfGroups*
2564 SMESH_MeshEditor_i::ExtrusionSweepObjects(const SMESH::ListOfIDSources & theNodes,
2565                                           const SMESH::ListOfIDSources & theEdges,
2566                                           const SMESH::ListOfIDSources & theFaces,
2567                                           const SMESH::DirStruct &       theStepVector,
2568                                           CORBA::Long                    theNbOfSteps,
2569                                           CORBA::Boolean                 theToMakeGroups)
2570   throw (SALOME::SALOME_Exception)
2571 {
2572   SMESH_TRY;
2573   initData();
2574
2575   ExtrusionParams params( theStepVector, theNbOfSteps, theToMakeGroups );
2576
2577   TIDSortedElemSet elemsNodes[2];
2578   for ( int i = 0, nb = theNodes.length(); i < nb; ++i ) {
2579     SMDS_ElemIteratorPtr nIt = myMesh_i->GetElements( theNodes[i], SMESH::NODE );
2580     while ( nIt->more() ) elemsNodes[1].insert( nIt->next() );
2581   }
2582   for ( int i = 0, nb = theEdges.length(); i < nb; ++i )
2583     idSourceToSet( theEdges[i], getMeshDS(), elemsNodes[0], SMDSAbs_Edge );
2584   for ( int i = 0, nb = theFaces.length(); i < nb; ++i )
2585     idSourceToSet( theFaces[i], getMeshDS(), elemsNodes[0], SMDSAbs_Face );
2586
2587   TIDSortedElemSet* workElements = & elemsNodes[0], copyElements[2];
2588   SMDSAbs_ElementType previewType = SMDSAbs_All; //SMDSAbs_Face;
2589   if ( myIsPreviewMode )
2590   {
2591     // if ( (*elemsNodes.begin())->GetType() == SMDSAbs_Node )
2592     //   previewType = SMDSAbs_Edge;
2593
2594     SMDSAbs_ElementType select = SMDSAbs_All, avoid = SMDSAbs_Volume;
2595     TPreviewMesh * tmpMesh = getPreviewMesh( previewType );
2596     tmpMesh->Copy( elemsNodes[0], copyElements[0], select, avoid );
2597     tmpMesh->Copy( elemsNodes[1], copyElements[1], select, avoid );
2598     workElements = & copyElements[0];
2599
2600     params.SetNoGroups();
2601   }
2602   TPythonDump aPythonDump; // it is here to prevent dump of getGroups()
2603
2604   ::SMESH_MeshEditor::TTElemOfElemListMap aHistory;
2605   ::SMESH_MeshEditor::PGroupIDs groupIds =
2606       getEditor().ExtrusionSweep( workElements, params, aHistory );
2607
2608   SMESH::ListOfGroups * aGroups = theToMakeGroups ? getGroups( groupIds.get()) : 0;
2609
2610   declareMeshModified( /*isReComputeSafe=*/true ); // does not influence Compute()
2611
2612   if ( !myIsPreviewMode )
2613   {
2614     dumpGroupsList( aPythonDump, aGroups );
2615     aPythonDump << this<< ".ExtrusionSweepObjects( "
2616                 << theNodes             << ", "
2617                 << theEdges             << ", "
2618                 << theFaces             << ", "
2619                 << theStepVector        << ", "
2620                 << TVar( theNbOfSteps ) << ", "
2621                 << theToMakeGroups      << " )";
2622   }
2623   else
2624   {
2625     getPreviewMesh( previewType )->Remove( SMDSAbs_Volume );
2626   }
2627
2628   return aGroups ? aGroups : new SMESH::ListOfGroups;
2629
2630   SMESH_CATCH( SMESH::throwCorbaException );
2631   return 0;
2632 }
2633
2634 //=======================================================================
2635 //function : ExtrusionByNormal
2636 //purpose  :
2637 //=======================================================================
2638
2639 SMESH::ListOfGroups*
2640 SMESH_MeshEditor_i::ExtrusionByNormal(const SMESH::ListOfIDSources& objects,
2641                                       CORBA::Double                 stepSize,
2642                                       CORBA::Long                   nbOfSteps,
2643                                       CORBA::Boolean                byAverageNormal,
2644                                       CORBA::Boolean                useInputElemsOnly,
2645                                       CORBA::Boolean                makeGroups,
2646                                       CORBA::Short                  dim)
2647   throw (SALOME::SALOME_Exception)
2648 {
2649   SMESH_TRY;
2650   initData();
2651
2652   TPythonDump aPythonDump; // it is here to prevent dump of GetGroups()
2653
2654   ExtrusionParams params( stepSize, nbOfSteps, dim,
2655                           byAverageNormal, useInputElemsOnly, makeGroups );
2656
2657   SMDSAbs_ElementType elemType = ( dim == 1 ? SMDSAbs_Edge : SMDSAbs_Face );
2658   if ( objects.length() > 0 && !SMESH::DownCast<SMESH_Mesh_i*>( objects[0] ))
2659   {
2660     SMESH::array_of_ElementType_var elemTypes = objects[0]->GetTypes();
2661     if (( elemTypes->length() == 1 ) &&
2662         ( elemTypes[0] == SMESH::EDGE || elemTypes[0] == SMESH::FACE ))
2663       elemType = ( SMDSAbs_ElementType ) elemTypes[0];
2664   }
2665
2666   TIDSortedElemSet elemsNodes[2];
2667   for ( int i = 0, nb = objects.length(); i < nb; ++i )
2668     idSourceToSet( objects[i], getMeshDS(), elemsNodes[0], elemType );
2669
2670   TIDSortedElemSet* workElements = & elemsNodes[0], copyElements[2];
2671   SMDSAbs_ElementType previewType = SMDSAbs_Face;
2672   if ( myIsPreviewMode )
2673   {
2674     SMDSAbs_ElementType select = SMDSAbs_All, avoid = SMDSAbs_Volume;
2675     TPreviewMesh * tmpMesh = getPreviewMesh( previewType );
2676     tmpMesh->Copy( elemsNodes[0], copyElements[0], select, avoid );
2677     workElements = & copyElements[0];
2678
2679     params.SetNoGroups();
2680   }
2681
2682   ::SMESH_MeshEditor::TTElemOfElemListMap aHistory;
2683   ::SMESH_MeshEditor::PGroupIDs groupIds =
2684       getEditor().ExtrusionSweep( workElements, params, aHistory );
2685
2686   SMESH::ListOfGroups * aGroups = makeGroups ? getGroups( groupIds.get()) : 0;
2687
2688   if (!myIsPreviewMode) {
2689     dumpGroupsList(aPythonDump, aGroups);
2690     aPythonDump << this << ".ExtrusionByNormal( " << objects
2691                 << ", " << TVar( stepSize )
2692                 << ", " << TVar( nbOfSteps )
2693                 << ", " << byAverageNormal
2694                 << ", " << useInputElemsOnly
2695                 << ", " << makeGroups
2696                 << ", " << dim
2697                 << " )";
2698   }
2699   else
2700   {
2701     getPreviewMesh( previewType )->Remove( SMDSAbs_Volume );
2702   }
2703
2704   declareMeshModified( /*isReComputeSafe=*/true ); // does not influence Compute()
2705
2706   return aGroups ? aGroups : new SMESH::ListOfGroups;
2707
2708   SMESH_CATCH( SMESH::throwCorbaException );
2709   return 0;
2710 }
2711
2712 //=======================================================================
2713 //function : AdvancedExtrusion
2714 //purpose  :
2715 //=======================================================================
2716
2717 SMESH::ListOfGroups*
2718 SMESH_MeshEditor_i::AdvancedExtrusion(const SMESH::long_array & theIDsOfElements,
2719                                       const SMESH::DirStruct &  theStepVector,
2720                                       CORBA::Long               theNbOfSteps,
2721                                       CORBA::Long               theExtrFlags,
2722                                       CORBA::Double             theSewTolerance,
2723                                       CORBA::Boolean            theMakeGroups)
2724   throw (SALOME::SALOME_Exception)
2725 {
2726   SMESH_TRY;
2727   initData();
2728
2729   TPythonDump aPythonDump; // it is here to prevent dump of getGroups()
2730
2731   ExtrusionParams params( theStepVector, theNbOfSteps, theMakeGroups,
2732                           theExtrFlags, theSewTolerance );
2733
2734   TIDSortedElemSet elemsNodes[2];
2735   arrayToSet( theIDsOfElements, getMeshDS(), elemsNodes[0] );
2736
2737   ::SMESH_MeshEditor::TTElemOfElemListMap aHistory;
2738   ::SMESH_MeshEditor::PGroupIDs groupIds =
2739       getEditor().ExtrusionSweep( elemsNodes, params, aHistory );
2740
2741   SMESH::ListOfGroups * aGroups = theMakeGroups ? getGroups( groupIds.get()) : 0;
2742
2743   declareMeshModified( /*isReComputeSafe=*/true ); // does not influence Compute()
2744
2745   if ( !myIsPreviewMode ) {
2746     dumpGroupsList(aPythonDump, aGroups);
2747     aPythonDump << this << ".AdvancedExtrusion( "
2748                 << theIDsOfElements << ", "
2749                 << theStepVector << ", "
2750                 << theNbOfSteps << ", "
2751                 << theExtrFlags << ", "
2752                 << theSewTolerance << ", "
2753                 << theMakeGroups << " )";
2754   }
2755   else
2756   {
2757     getPreviewMesh()->Remove( SMDSAbs_Volume );
2758   }
2759
2760   return aGroups ? aGroups : new SMESH::ListOfGroups;
2761
2762   SMESH_CATCH( SMESH::throwCorbaException );
2763   return 0;
2764 }
2765
2766 //================================================================================
2767 /*!
2768  * \brief Convert extrusion error to IDL enum
2769  */
2770 //================================================================================
2771
2772 namespace
2773 {
2774 #define RETCASE(enm) case ::SMESH_MeshEditor::enm: return SMESH::SMESH_MeshEditor::enm;
2775
2776   SMESH::SMESH_MeshEditor::Extrusion_Error convExtrError( ::SMESH_MeshEditor::Extrusion_Error e )
2777   {
2778     switch ( e ) {
2779       RETCASE( EXTR_OK );
2780       RETCASE( EXTR_NO_ELEMENTS );
2781       RETCASE( EXTR_PATH_NOT_EDGE );
2782       RETCASE( EXTR_BAD_PATH_SHAPE );
2783       RETCASE( EXTR_BAD_STARTING_NODE );
2784       RETCASE( EXTR_BAD_ANGLES_NUMBER );
2785       RETCASE( EXTR_CANT_GET_TANGENT );
2786     }
2787     return SMESH::SMESH_MeshEditor::EXTR_OK;
2788   }
2789 }
2790
2791 //=======================================================================
2792 //function : extrusionAlongPath
2793 //purpose  :
2794 //=======================================================================
2795 SMESH::ListOfGroups*
2796 SMESH_MeshEditor_i::ExtrusionAlongPathObjects(const SMESH::ListOfIDSources & theNodes,
2797                                               const SMESH::ListOfIDSources & theEdges,
2798                                               const SMESH::ListOfIDSources & theFaces,
2799                                               SMESH::SMESH_IDSource_ptr      thePathMesh,
2800                                               GEOM::GEOM_Object_ptr          thePathShape,
2801                                               CORBA::Long                    theNodeStart,
2802                                               CORBA::Boolean                 theHasAngles,
2803                                               const SMESH::double_array &    theAngles,
2804                                               CORBA::Boolean                 theLinearVariation,
2805                                               CORBA::Boolean                 theHasRefPoint,
2806                                               const SMESH::PointStruct &     theRefPoint,
2807                                               bool                           theMakeGroups,
2808                                               SMESH::SMESH_MeshEditor::Extrusion_Error& theError)
2809   throw (SALOME::SALOME_Exception)
2810 {
2811   SMESH_TRY;
2812   initData();
2813
2814   SMESH::ListOfGroups_var aGroups = new SMESH::ListOfGroups;
2815
2816   theError = SMESH::SMESH_MeshEditor::EXTR_BAD_PATH_SHAPE;
2817   if ( thePathMesh->_is_nil() )
2818     return aGroups._retn();
2819
2820   // get a sub-mesh
2821   SMESH_subMesh* aSubMesh = 0;
2822   SMESH_Mesh_i* aMeshImp = SMESH::DownCast<SMESH_Mesh_i*>( thePathMesh );
2823   if ( thePathShape->_is_nil() )
2824   {
2825     // thePathMesh should be either a sub-mesh or a mesh with 1D elements only
2826     if ( SMESH_subMesh_i* sm = SMESH::DownCast<SMESH_subMesh_i*>( thePathMesh ))
2827     {
2828       SMESH::SMESH_Mesh_var mesh = thePathMesh->GetMesh();
2829       aMeshImp = SMESH::DownCast<SMESH_Mesh_i*>( mesh );
2830       if ( !aMeshImp ) return aGroups._retn();
2831       aSubMesh = aMeshImp->GetImpl().GetSubMeshContaining( sm->GetId() );
2832       if ( !aSubMesh ) return aGroups._retn();
2833     }
2834     else if ( !aMeshImp ||
2835               aMeshImp->NbEdges() != aMeshImp->NbElements() )
2836     {
2837       return aGroups._retn();
2838     }
2839   }
2840   else
2841   {
2842     if ( !aMeshImp ) return aGroups._retn();
2843     TopoDS_Shape aShape = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape( thePathShape );
2844     aSubMesh = aMeshImp->GetImpl().GetSubMesh( aShape );
2845     if ( !aSubMesh /*|| !aSubMesh->GetSubMeshDS()*/ )
2846       return aGroups._retn();
2847   }
2848
2849   SMDS_MeshNode* nodeStart =
2850     (SMDS_MeshNode*)aMeshImp->GetImpl().GetMeshDS()->FindNode(theNodeStart);
2851   if ( !nodeStart ) {
2852     theError = SMESH::SMESH_MeshEditor::EXTR_BAD_STARTING_NODE;
2853     return aGroups._retn();
2854   }
2855
2856   TIDSortedElemSet elemsNodes[2];
2857   for ( int i = 0, nb = theNodes.length(); i < nb; ++i ) {
2858     SMDS_ElemIteratorPtr nIt = myMesh_i->GetElements( theNodes[i], SMESH::NODE );
2859     while ( nIt->more() ) elemsNodes[1].insert( nIt->next() );
2860   }
2861   for ( int i = 0, nb = theEdges.length(); i < nb; ++i )
2862     idSourceToSet( theEdges[i], getMeshDS(), elemsNodes[0], SMDSAbs_Edge );
2863   for ( int i = 0, nb = theFaces.length(); i < nb; ++i )
2864     idSourceToSet( theFaces[i], getMeshDS(), elemsNodes[0], SMDSAbs_Face );
2865
2866   list<double> angles;
2867   for ( CORBA::ULong i = 0; i < theAngles.length(); i++ ) {
2868     angles.push_back( theAngles[i] );
2869   }
2870
2871   gp_Pnt refPnt( theRefPoint.x, theRefPoint.y, theRefPoint.z );
2872
2873   int nbOldGroups = myMesh->NbGroup();
2874
2875   TIDSortedElemSet* workElements = & elemsNodes[0], copyElements[2];
2876   if ( myIsPreviewMode )
2877   {
2878     SMDSAbs_ElementType select = SMDSAbs_All, avoid = SMDSAbs_Volume;
2879     TPreviewMesh * tmpMesh = getPreviewMesh();
2880     tmpMesh->Copy( elemsNodes[0], copyElements[0], select, avoid );
2881     tmpMesh->Copy( elemsNodes[1], copyElements[1], select, avoid );
2882     workElements = & copyElements[0];
2883     theMakeGroups = false;
2884   }
2885
2886   ::SMESH_MeshEditor::Extrusion_Error error;
2887   if ( !aSubMesh )
2888     error = getEditor().ExtrusionAlongTrack( workElements, &(aMeshImp->GetImpl()), nodeStart,
2889                                              theHasAngles, angles, theLinearVariation,
2890                                              theHasRefPoint, refPnt, theMakeGroups );
2891   else
2892     error = getEditor().ExtrusionAlongTrack( workElements, aSubMesh, nodeStart,
2893                                              theHasAngles, angles, theLinearVariation,
2894                                              theHasRefPoint, refPnt, theMakeGroups );
2895
2896   declareMeshModified( /*isReComputeSafe=*/true );
2897   theError = convExtrError( error );
2898
2899   TPythonDump aPythonDump; // it is here to prevent dump of getGroups()
2900   if ( theMakeGroups ) {
2901     list<int> groupIDs = myMesh->GetGroupIds();
2902     list<int>::iterator newBegin = groupIDs.begin();
2903     std::advance( newBegin, nbOldGroups ); // skip old groups
2904     groupIDs.erase( groupIDs.begin(), newBegin );
2905     aGroups = getGroups( & groupIDs );
2906     if ( ! &aGroups.in() ) aGroups = new SMESH::ListOfGroups;
2907   }
2908
2909   if ( !myIsPreviewMode ) {
2910     aPythonDump << "(" << aGroups << ", error) = "
2911                 << this << ".ExtrusionAlongPathObjects( "
2912                 << theNodes            << ", "
2913                 << theEdges            << ", "
2914                 << theFaces            << ", "
2915                 << thePathMesh         << ", "
2916                 << thePathShape        << ", "
2917                 << theNodeStart        << ", "
2918                 << theHasAngles        << ", "
2919                 << theAngles           << ", "
2920                 << theLinearVariation  << ", "
2921                 << theHasRefPoint      << ", "
2922                 << "SMESH.PointStruct( "
2923                 << ( theHasRefPoint ? theRefPoint.x : 0 ) << ", "
2924                 << ( theHasRefPoint ? theRefPoint.y : 0 ) << ", "
2925                 << ( theHasRefPoint ? theRefPoint.z : 0 ) << " ), "
2926                 << theMakeGroups       << " )";
2927   }
2928   else
2929   {
2930     getPreviewMesh()->Remove( SMDSAbs_Volume );
2931   }
2932
2933   return aGroups._retn();
2934
2935   SMESH_CATCH( SMESH::throwCorbaException );
2936   return 0;
2937 }
2938
2939 //================================================================================
2940 /*!
2941  * \brief Compute rotation angles for ExtrusionAlongPath as linear variation
2942  * of given angles along path steps
2943  * \param PathMesh mesh containing a 1D sub-mesh on the edge, along
2944  *                which proceeds the extrusion
2945  * \param PathShape is shape(edge); as the mesh can be complex, the edge
2946  *                 is used to define the sub-mesh for the path
2947  */
2948 //================================================================================
2949
2950 SMESH::double_array*
2951 SMESH_MeshEditor_i::LinearAnglesVariation(SMESH::SMESH_Mesh_ptr       thePathMesh,
2952                                           GEOM::GEOM_Object_ptr       thePathShape,
2953                                           const SMESH::double_array & theAngles)
2954 {
2955   SMESH::double_array_var aResult = new SMESH::double_array();
2956   int nbAngles = theAngles.length();
2957   if ( nbAngles > 0 && !thePathMesh->_is_nil() && !thePathShape->_is_nil() )
2958   {
2959     SMESH_Mesh_i* aMeshImp = SMESH::DownCast<SMESH_Mesh_i*>( thePathMesh );
2960     TopoDS_Shape aShape = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape( thePathShape );
2961     SMESH_subMesh* aSubMesh = aMeshImp->GetImpl().GetSubMesh( aShape );
2962     if ( !aSubMesh || !aSubMesh->GetSubMeshDS())
2963       return aResult._retn();
2964     int nbSteps = aSubMesh->GetSubMeshDS()->NbElements();
2965     if ( nbSteps == nbAngles )
2966     {
2967       aResult.inout() = theAngles;
2968     }
2969     else
2970     {
2971       aResult->length( nbSteps );
2972       double rAn2St = double( nbAngles ) / double( nbSteps );
2973       double angPrev = 0, angle;
2974       for ( int iSt = 0; iSt < nbSteps; ++iSt )
2975       {
2976         double angCur = rAn2St * ( iSt+1 );
2977         double angCurFloor  = floor( angCur );
2978         double angPrevFloor = floor( angPrev );
2979         if ( angPrevFloor == angCurFloor )
2980           angle = rAn2St * theAngles[ int( angCurFloor ) ];
2981         else
2982         {
2983           int iP = int( angPrevFloor );
2984           double angPrevCeil = ceil(angPrev);
2985           angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
2986
2987           int iC = int( angCurFloor );
2988           if ( iC < nbAngles )
2989             angle += ( angCur - angCurFloor ) * theAngles[ iC ];
2990
2991           iP = int( angPrevCeil );
2992           while ( iC-- > iP )
2993             angle += theAngles[ iC ];
2994         }
2995         aResult[ iSt ] = angle;
2996         angPrev = angCur;
2997       }
2998     }
2999   }
3000   // Update Python script
3001   TPythonDump() << "rotAngles = " << theAngles;
3002   TPythonDump() << "rotAngles = " << this << ".LinearAnglesVariation( "
3003                 << thePathMesh  << ", "
3004                 << thePathShape << ", "
3005                 << "rotAngles )";
3006
3007   return aResult._retn();
3008 }
3009
3010 //=======================================================================
3011 //function : mirror
3012 //purpose  :
3013 //=======================================================================
3014
3015 SMESH::ListOfGroups*
3016 SMESH_MeshEditor_i::mirror(TIDSortedElemSet &                  theElements,
3017                            const SMESH::AxisStruct &           theAxis,
3018                            SMESH::SMESH_MeshEditor::MirrorType theMirrorType,
3019                            CORBA::Boolean                      theCopy,
3020                            bool                                theMakeGroups,
3021                            ::SMESH_Mesh*                       theTargetMesh)
3022   throw (SALOME::SALOME_Exception)
3023 {
3024   SMESH_TRY;
3025   initData();
3026
3027   gp_Pnt P ( theAxis.x, theAxis.y, theAxis.z );
3028   gp_Vec V ( theAxis.vx, theAxis.vy, theAxis.vz );
3029
3030   if ( theTargetMesh )
3031     theCopy = false;
3032
3033   gp_Trsf aTrsf;
3034   switch ( theMirrorType ) {
3035   case  SMESH::SMESH_MeshEditor::POINT:
3036     aTrsf.SetMirror( P );
3037     break;
3038   case  SMESH::SMESH_MeshEditor::AXIS:
3039     aTrsf.SetMirror( gp_Ax1( P, V ));
3040     break;
3041   default:
3042     aTrsf.SetMirror( gp_Ax2( P, V ));
3043   }
3044
3045   TIDSortedElemSet  copyElements;
3046   TIDSortedElemSet* workElements = & theElements;
3047
3048   if ( myIsPreviewMode )
3049   {
3050     TPreviewMesh * tmpMesh = getPreviewMesh();
3051     tmpMesh->Copy( theElements, copyElements);
3052     if ( !theCopy && !theTargetMesh )
3053     {
3054       TIDSortedElemSet elemsAround, elemsAroundCopy;
3055       getElementsAround( theElements, getMeshDS(), elemsAround );
3056       tmpMesh->Copy( elemsAround, elemsAroundCopy);
3057     }
3058     workElements = & copyElements;
3059     theMakeGroups = false;
3060   }
3061
3062   ::SMESH_MeshEditor::PGroupIDs groupIds =
3063       getEditor().Transform (*workElements, aTrsf, theCopy, theMakeGroups, theTargetMesh);
3064
3065   if ( theCopy && !myIsPreviewMode)
3066   {
3067     if ( theTargetMesh )
3068     {
3069       theTargetMesh->GetMeshDS()->Modified();
3070     }
3071     else
3072     {
3073       declareMeshModified( /*isReComputeSafe=*/false );
3074     }
3075   }
3076   return theMakeGroups ? getGroups(groupIds.get()) : 0;
3077
3078   SMESH_CATCH( SMESH::throwCorbaException );