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