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