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