Salome HOME
23023: [CEA 1445] missing ExtrusionAlongPathObject function
[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 Returns the mesh
445  */
446 //================================================================================
447
448 SMESH::SMESH_Mesh_ptr SMESH_MeshEditor_i::GetMesh()
449 {
450   return myMesh_i->_this();
451 }
452
453 //================================================================================
454 /*!
455  * \brief Clear members
456  */
457 //================================================================================
458
459 void SMESH_MeshEditor_i::initData(bool deleteSearchers)
460 {
461   if ( myIsPreviewMode ) {
462     if ( myPreviewMesh ) myPreviewMesh->RemoveAll();
463   }
464   else {
465     if ( deleteSearchers )
466       TSearchersDeleter::Delete();
467   }
468   getEditor().GetError().reset();
469   getEditor().ClearLastCreated();
470 }
471
472 //================================================================================
473 /*!
474  * \brief Increment mesh modif time and optionally record that the performed
475  *        modification may influence futher mesh re-compute.
476  *  \param [in] isReComputeSafe - true if the modification does not infulence
477  *              futher mesh re-compute
478  */
479 //================================================================================
480
481 void SMESH_MeshEditor_i::declareMeshModified( bool isReComputeSafe )
482 {
483   myMesh->GetMeshDS()->Modified();
484   if ( !isReComputeSafe )
485     myMesh->SetIsModified( true );
486 }
487
488 //================================================================================
489 /*!
490  * \brief Return either myEditor or myPreviewEditor depending on myIsPreviewMode.
491  *        WARNING: in preview mode call getPreviewMesh() before getEditor()!
492  */
493 //================================================================================
494
495 ::SMESH_MeshEditor& SMESH_MeshEditor_i::getEditor()
496 {
497   if ( myIsPreviewMode && !myPreviewEditor ) {
498     if ( !myPreviewMesh ) getPreviewMesh();
499     myPreviewEditor = new ::SMESH_MeshEditor( myPreviewMesh );
500   }
501   return myIsPreviewMode ? *myPreviewEditor : myEditor;
502 }
503
504 //================================================================================
505 /*!
506  * \brief Initialize and return myPreviewMesh
507  *  \param previewElements - type of elements to show in preview
508  *
509  *  WARNING: call it once par a method!
510  */
511 //================================================================================
512
513 TPreviewMesh * SMESH_MeshEditor_i::getPreviewMesh(SMDSAbs_ElementType previewElements)
514 {
515   if ( !myPreviewMesh || myPreviewMesh->myPreviewType != previewElements )
516   {
517     delete myPreviewEditor;
518     myPreviewEditor = 0;
519     delete myPreviewMesh;
520     myPreviewMesh = new TPreviewMesh( previewElements );
521   }
522   myPreviewMesh->Clear();
523   return myPreviewMesh;
524 }
525
526 //================================================================================
527 /*!
528  * Return data of mesh edition preview
529  */
530 //================================================================================
531
532 SMESH::MeshPreviewStruct* SMESH_MeshEditor_i::GetPreviewData()
533   throw (SALOME::SALOME_Exception)
534
535   SMESH_TRY;
536   const bool hasBadElems = ( getEditor().GetError() && getEditor().GetError()->HasBadElems() );
537
538   if ( myIsPreviewMode || hasBadElems ) { // --- MeshPreviewStruct filling ---
539
540     list<int> aNodesConnectivity;
541     typedef map<int, int> TNodesMap;
542     TNodesMap nodesMap;
543
544     SMESHDS_Mesh* aMeshDS;
545     std::auto_ptr< SMESH_MeshPartDS > aMeshPartDS;
546     if ( hasBadElems ) {
547       aMeshPartDS.reset( new SMESH_MeshPartDS( getEditor().GetError()->myBadElements ));
548       aMeshDS = aMeshPartDS.get();
549     }
550     else {
551       aMeshDS = getEditor().GetMeshDS();
552     }
553     myPreviewData = new SMESH::MeshPreviewStruct();
554     myPreviewData->nodesXYZ.length(aMeshDS->NbNodes());
555
556     
557     SMDSAbs_ElementType previewType = SMDSAbs_All;
558     if ( !hasBadElems )
559       if (TPreviewMesh * aPreviewMesh = dynamic_cast< TPreviewMesh* >( getEditor().GetMesh() )) {
560         previewType = aPreviewMesh->myPreviewType;
561         switch ( previewType ) {
562         case SMDSAbs_Edge  : break;
563         case SMDSAbs_Face  : break;
564         case SMDSAbs_Volume: break;
565         default:;
566           if ( aMeshDS->GetMeshInfo().NbElements() == 0 ) previewType = SMDSAbs_Node;
567         }
568       }
569
570     myPreviewData->elementTypes.length( aMeshDS->GetMeshInfo().NbElements( previewType ));
571     int i = 0, j = 0;
572     SMDS_ElemIteratorPtr itMeshElems = aMeshDS->elementsIterator(previewType);
573
574     while ( itMeshElems->more() ) {
575       const SMDS_MeshElement* aMeshElem = itMeshElems->next();
576       SMDS_NodeIteratorPtr itElemNodes = aMeshElem->nodeIterator();
577       while ( itElemNodes->more() ) {
578         const SMDS_MeshNode* aMeshNode = itElemNodes->next();
579         int aNodeID = aMeshNode->GetID();
580         TNodesMap::iterator anIter = nodesMap.find(aNodeID);
581         if ( anIter == nodesMap.end() ) {
582           // filling the nodes coordinates
583           myPreviewData->nodesXYZ[j].x = aMeshNode->X();
584           myPreviewData->nodesXYZ[j].y = aMeshNode->Y();
585           myPreviewData->nodesXYZ[j].z = aMeshNode->Z();
586           anIter = nodesMap.insert( make_pair(aNodeID, j) ).first;
587           j++;
588         }
589         aNodesConnectivity.push_back(anIter->second);
590       }
591
592       // filling the elements types
593       SMDSAbs_ElementType aType = aMeshElem->GetType();
594       bool               isPoly = aMeshElem->IsPoly();
595       myPreviewData->elementTypes[i].SMDS_ElementType = (SMESH::ElementType) aType;
596       myPreviewData->elementTypes[i].isPoly           = isPoly;
597       myPreviewData->elementTypes[i].nbNodesInElement = aMeshElem->NbNodes();
598       i++;
599     }
600     myPreviewData->nodesXYZ.length( j );
601
602     // filling the elements connectivities
603     list<int>::iterator aConnIter = aNodesConnectivity.begin();
604     myPreviewData->elementConnectivities.length(aNodesConnectivity.size());
605     for( int i = 0; aConnIter != aNodesConnectivity.end(); aConnIter++, i++ )
606       myPreviewData->elementConnectivities[i] = *aConnIter;
607   }
608   return myPreviewData._retn();
609
610   SMESH_CATCH( SMESH::throwCorbaException );
611   return 0;
612 }
613
614 //================================================================================
615 /*!
616  * \brief Returns list of it's IDs of created nodes
617  * \retval SMESH::long_array* - list of node ID
618  */
619 //================================================================================
620
621 SMESH::long_array* SMESH_MeshEditor_i::GetLastCreatedNodes()
622   throw (SALOME::SALOME_Exception)
623 {
624   SMESH_TRY;
625   SMESH::long_array_var myLastCreatedNodes = new SMESH::long_array();
626
627   const SMESH_SequenceOfElemPtr& aSeq = getEditor().GetLastCreatedNodes();
628   myLastCreatedNodes->length( aSeq.Length() );
629   for (int i = 1; i <= aSeq.Length(); i++)
630     myLastCreatedNodes[i-1] = aSeq.Value(i)->GetID();
631
632   return myLastCreatedNodes._retn();
633   SMESH_CATCH( SMESH::throwCorbaException );
634   return 0;
635 }
636
637 //================================================================================
638 /*!
639  * \brief Returns list of it's IDs of created elements
640  * \retval SMESH::long_array* - list of elements' ID
641  */
642 //================================================================================
643
644 SMESH::long_array* SMESH_MeshEditor_i::GetLastCreatedElems()
645   throw (SALOME::SALOME_Exception)
646 {
647   SMESH_TRY;
648   SMESH::long_array_var myLastCreatedElems = new SMESH::long_array();
649
650   const SMESH_SequenceOfElemPtr& aSeq = getEditor().GetLastCreatedElems();
651   myLastCreatedElems->length( aSeq.Length() );
652   for ( int i = 1; i <= aSeq.Length(); i++ )
653     myLastCreatedElems[i-1] = aSeq.Value(i)->GetID();
654
655   return myLastCreatedElems._retn();
656   SMESH_CATCH( SMESH::throwCorbaException );
657   return 0;
658 }
659
660 //=======================================================================
661 //function : ClearLastCreated
662 //purpose  : Clears sequences of last created elements and nodes 
663 //=======================================================================
664
665 void SMESH_MeshEditor_i::ClearLastCreated() throw (SALOME::SALOME_Exception)
666 {
667   SMESH_TRY;
668   getEditor().ClearLastCreated();
669   SMESH_CATCH( SMESH::throwCorbaException );
670 }
671
672 //=======================================================================
673 /*
674  * Returns description of an error/warning occured during the last operation
675  * WARNING: ComputeError.code >= 100 and no corresponding enum in IDL API
676  */
677 //=======================================================================
678
679 SMESH::ComputeError* SMESH_MeshEditor_i::GetLastError()
680   throw (SALOME::SALOME_Exception)
681 {
682   SMESH_TRY;
683   SMESH::ComputeError_var errOut = new SMESH::ComputeError;
684   SMESH_ComputeErrorPtr&  errIn  = getEditor().GetError();
685   if ( errIn && !errIn->IsOK() )
686   {
687     errOut->code       = -( errIn->myName < 0 ? errIn->myName + 1: errIn->myName ); // -1 -> 0
688     errOut->comment    = errIn->myComment.c_str();
689     errOut->subShapeID = -1;
690     errOut->hasBadMesh = !errIn->myBadElements.empty();
691   }
692   else
693   {
694     errOut->code       = 0;
695     errOut->subShapeID = -1;
696     errOut->hasBadMesh = false;
697   }
698
699   return errOut._retn();
700   SMESH_CATCH( SMESH::throwCorbaException );
701   return 0;
702 }
703
704 //=======================================================================
705 //function : MakeIDSource
706 //purpose  : Wrap a sequence of ids in a SMESH_IDSource.
707 //           Call UnRegister() as you fininsh using it!!
708 //=======================================================================
709
710 struct SMESH_MeshEditor_i::_IDSource : public virtual POA_SMESH::SMESH_IDSource,
711                                        public virtual SALOME::GenericObj_i
712 {
713   SMESH::long_array     _ids;
714   SMESH::ElementType    _type;
715   SMESH::SMESH_Mesh_ptr _mesh;
716   SMESH::long_array* GetIDs()      { return new SMESH::long_array( _ids ); }
717   SMESH::long_array* GetMeshInfo() { return 0; }
718   SMESH::long_array* GetNbElementsByType()
719   {
720     SMESH::long_array_var aRes = new SMESH::long_array();
721     aRes->length(SMESH::NB_ELEMENT_TYPES);
722     for (int i = 0; i < SMESH::NB_ELEMENT_TYPES; i++)
723       aRes[ i ] = ( i == _type ) ? _ids.length() : 0;
724     return aRes._retn();  
725   }
726   SMESH::SMESH_Mesh_ptr GetMesh()  { return SMESH::SMESH_Mesh::_duplicate( _mesh ); }
727   bool IsMeshInfoCorrect()         { return true; }
728   SMESH::array_of_ElementType* GetTypes()
729   {
730     SMESH::array_of_ElementType_var types = new SMESH::array_of_ElementType;
731     if ( _ids.length() > 0 ) {
732       types->length( 1 );
733       types[0] = _type;
734     }
735     return types._retn();
736   }
737   SALOMEDS::TMPFile* GetVtkUgStream()
738   {
739     SALOMEDS::TMPFile_var SeqFile;
740     return SeqFile._retn();
741   }
742 };
743
744 SMESH::SMESH_IDSource_ptr SMESH_MeshEditor_i::MakeIDSource(const SMESH::long_array& ids,
745                                                            SMESH::ElementType       type)
746 {
747   _IDSource* idSrc = new _IDSource;
748   idSrc->_mesh = myMesh_i->_this();
749   idSrc->_ids  = ids;
750   idSrc->_type = type;
751   if ( type == SMESH::ALL && ids.length() > 0 )
752     idSrc->_type = myMesh_i->GetElementType( ids[0], true );
753
754   SMESH::SMESH_IDSource_var anIDSourceVar = idSrc->_this();
755
756   return anIDSourceVar._retn();
757 }
758
759 bool SMESH_MeshEditor_i::IsTemporaryIDSource( SMESH::SMESH_IDSource_ptr& idSource )
760 {
761   return SMESH::DownCast<SMESH_MeshEditor_i::_IDSource*>( idSource );
762 }
763
764 CORBA::Long* SMESH_MeshEditor_i::GetTemporaryIDs( SMESH::SMESH_IDSource_ptr& idSource,
765                                                   int&                       nbIds)
766 {
767   if ( _IDSource* tmpIdSource = SMESH::DownCast<SMESH_MeshEditor_i::_IDSource*>( idSource ))
768   {
769     nbIds = (int) tmpIdSource->_ids.length();
770     return & tmpIdSource->_ids[0];
771   }
772   nbIds = 0;
773   return 0;
774 }
775
776 // void SMESH_MeshEditor_i::deleteAuxIDSources()
777 // {
778 //   std::list< _IDSource* >::iterator idSrcIt = myAuxIDSources.begin();
779 //   for ( ; idSrcIt != myAuxIDSources.end(); ++idSrcIt )
780 //     delete *idSrcIt;
781 //   myAuxIDSources.clear();
782 // }
783
784 //=============================================================================
785 /*!
786  *
787  */
788 //=============================================================================
789
790 CORBA::Boolean
791 SMESH_MeshEditor_i::RemoveElements(const SMESH::long_array & IDsOfElements)
792   throw (SALOME::SALOME_Exception)
793 {
794   SMESH_TRY;
795   initData();
796
797   list< int > IdList;
798
799   for (int i = 0; i < IDsOfElements.length(); i++)
800     IdList.push_back( IDsOfElements[i] );
801
802   // Update Python script
803   TPythonDump() << "isDone = " << this << ".RemoveElements( " << IDsOfElements << " )";
804
805   // Remove Elements
806   bool ret = getEditor().Remove( IdList, false );
807
808   declareMeshModified( /*isReComputeSafe=*/ IDsOfElements.length() == 0 ); // issue 0020693
809   return ret;
810
811   SMESH_CATCH( SMESH::throwCorbaException );
812   return 0;
813 }
814
815 //=============================================================================
816 /*!
817  *
818  */
819 //=============================================================================
820
821 CORBA::Boolean SMESH_MeshEditor_i::RemoveNodes(const SMESH::long_array & IDsOfNodes)
822   throw (SALOME::SALOME_Exception)
823 {
824   SMESH_TRY;
825   initData();
826
827   list< int > IdList;
828   for (int i = 0; i < IDsOfNodes.length(); i++)
829     IdList.push_back( IDsOfNodes[i] );
830
831   // Update Python script
832   TPythonDump() << "isDone = " << this << ".RemoveNodes( " << IDsOfNodes << " )";
833
834   bool ret = getEditor().Remove( IdList, true );
835
836   declareMeshModified( /*isReComputeSafe=*/ !ret ); // issue 0020693
837   return ret;
838
839   SMESH_CATCH( SMESH::throwCorbaException );
840   return 0;
841 }
842
843 //=============================================================================
844 /*!
845  *
846  */
847 //=============================================================================
848
849 CORBA::Long SMESH_MeshEditor_i::RemoveOrphanNodes()
850   throw (SALOME::SALOME_Exception)
851 {
852   SMESH_TRY;
853   initData();
854
855   // Update Python script
856   TPythonDump() << "nbRemoved = " << this << ".RemoveOrphanNodes()";
857
858   // Create filter to find all orphan nodes
859   SMESH::Controls::Filter::TIdSequence seq;
860   SMESH::Controls::PredicatePtr predicate( new SMESH::Controls::FreeNodes() );
861   SMESH::Controls::Filter::GetElementsId( getMeshDS(), predicate, seq );
862
863   // remove orphan nodes (if there are any)
864   list< int > IdList;
865   for ( int i = 0; i < seq.size(); i++ )
866     IdList.push_back( seq[i] );
867
868   int nbNodesBefore = myMesh->NbNodes();
869   getEditor().Remove( IdList, true );
870   int nbNodesAfter = myMesh->NbNodes();
871
872   declareMeshModified( /*isReComputeSafe=*/ IdList.size() == 0 ); // issue 0020693
873   return nbNodesBefore - nbNodesAfter;
874
875   SMESH_CATCH( SMESH::throwCorbaException );
876   return 0;
877 }
878
879 //=============================================================================
880 /*!
881  * Add a new node.
882  */
883 //=============================================================================
884
885 CORBA::Long SMESH_MeshEditor_i::AddNode(CORBA::Double x,CORBA::Double y, CORBA::Double z)
886   throw (SALOME::SALOME_Exception)
887 {
888   SMESH_TRY;
889   initData();
890
891   const SMDS_MeshNode* N = getMeshDS()->AddNode(x, y, z);
892
893   // Update Python script
894   TPythonDump() << "nodeID = " << this << ".AddNode( "
895                 << TVar( x ) << ", " << TVar( y ) << ", " << TVar( z )<< " )";
896
897   declareMeshModified( /*isReComputeSafe=*/false );
898   return N->GetID();
899
900   SMESH_CATCH( SMESH::throwCorbaException );
901   return 0;
902 }
903
904 //=============================================================================
905 /*!
906  * Create 0D element on the given node.
907  */
908 //=============================================================================
909
910 CORBA::Long SMESH_MeshEditor_i::Add0DElement(CORBA::Long IDOfNode)
911   throw (SALOME::SALOME_Exception)
912 {
913   SMESH_TRY;
914   initData();
915
916   const SMDS_MeshNode* aNode = getMeshDS()->FindNode(IDOfNode);
917   SMDS_MeshElement* elem = getMeshDS()->Add0DElement(aNode);
918
919   // Update Python script
920   TPythonDump() << "elem0d = " << this << ".Add0DElement( " << IDOfNode <<" )";
921
922   declareMeshModified( /*isReComputeSafe=*/false );
923
924   return elem ? elem->GetID() : 0;
925
926   SMESH_CATCH( SMESH::throwCorbaException );
927   return 0;
928 }
929
930 //=============================================================================
931 /*!
932  * Create a ball element on the given node.
933  */
934 //=============================================================================
935
936 CORBA::Long SMESH_MeshEditor_i::AddBall(CORBA::Long IDOfNode, CORBA::Double diameter)
937   throw (SALOME::SALOME_Exception)
938 {
939   SMESH_TRY;
940   initData();
941
942   if ( diameter < std::numeric_limits<double>::min() )
943     THROW_SALOME_CORBA_EXCEPTION("Invalid diameter", SALOME::BAD_PARAM);
944
945   const SMDS_MeshNode* aNode = getMeshDS()->FindNode(IDOfNode);
946   SMDS_MeshElement* elem = getMeshDS()->AddBall(aNode, diameter);
947
948   // Update Python script
949   TPythonDump() << "ballElem = "
950                 << this << ".AddBall( " << IDOfNode << ", " << diameter <<" )";
951
952   declareMeshModified( /*isReComputeSafe=*/false );
953   return elem ? elem->GetID() : 0;
954
955   SMESH_CATCH( SMESH::throwCorbaException );
956   return 0;
957 }
958
959 //=============================================================================
960 /*!
961  * Create an edge, either linear and quadratic (this is determed
962  *  by number of given nodes, two or three)
963  */
964 //=============================================================================
965
966 CORBA::Long SMESH_MeshEditor_i::AddEdge(const SMESH::long_array & IDsOfNodes)
967   throw (SALOME::SALOME_Exception)
968 {
969   SMESH_TRY;
970   initData();
971
972   int NbNodes = IDsOfNodes.length();
973   SMDS_MeshElement* elem = 0;
974   if (NbNodes == 2)
975   {
976     CORBA::Long index1 = IDsOfNodes[0];
977     CORBA::Long index2 = IDsOfNodes[1];
978     elem = getMeshDS()->AddEdge( getMeshDS()->FindNode(index1),
979                                  getMeshDS()->FindNode(index2));
980
981     // Update Python script
982     TPythonDump() << "edge = " << this << ".AddEdge([ "
983                   << index1 << ", " << index2 <<" ])";
984   }
985   if (NbNodes == 3) {
986     CORBA::Long n1 = IDsOfNodes[0];
987     CORBA::Long n2 = IDsOfNodes[1];
988     CORBA::Long n12 = IDsOfNodes[2];
989     elem = getMeshDS()->AddEdge( getMeshDS()->FindNode(n1),
990                                  getMeshDS()->FindNode(n2),
991                                  getMeshDS()->FindNode(n12));
992     // Update Python script
993     TPythonDump() << "edgeID = " << this << ".AddEdge([ "
994                   <<n1<<", "<<n2<<", "<<n12<<" ])";
995   }
996
997   declareMeshModified( /*isReComputeSafe=*/false );
998   return elem ? elem->GetID() : 0;
999
1000   SMESH_CATCH( SMESH::throwCorbaException );
1001   return 0;
1002 }
1003
1004 //=============================================================================
1005 /*!
1006  *  AddFace
1007  */
1008 //=============================================================================
1009
1010 CORBA::Long SMESH_MeshEditor_i::AddFace(const SMESH::long_array & IDsOfNodes)
1011   throw (SALOME::SALOME_Exception)
1012 {
1013   SMESH_TRY;
1014   initData();
1015
1016   int NbNodes = IDsOfNodes.length();
1017   if (NbNodes < 3)
1018   {
1019     return 0;
1020   }
1021
1022   std::vector<const SMDS_MeshNode*> nodes (NbNodes);
1023   for (int i = 0; i < NbNodes; i++)
1024     nodes[i] = getMeshDS()->FindNode(IDsOfNodes[i]);
1025
1026   SMDS_MeshElement* elem = 0;
1027   switch (NbNodes) {
1028   case 3: elem = getMeshDS()->AddFace(nodes[0], nodes[1], nodes[2]); break;
1029   case 4: elem = getMeshDS()->AddFace(nodes[0], nodes[1], nodes[2], nodes[3]); break;
1030   case 6: elem = getMeshDS()->AddFace(nodes[0], nodes[1], nodes[2], nodes[3],
1031                                       nodes[4], nodes[5]); break;
1032   case 7: elem = getMeshDS()->AddFace(nodes[0], nodes[1], nodes[2], nodes[3],
1033                                       nodes[4], nodes[5], nodes[6]); break;
1034   case 8: elem = getMeshDS()->AddFace(nodes[0], nodes[1], nodes[2], nodes[3],
1035                                       nodes[4], nodes[5], nodes[6], nodes[7]); break;
1036   case 9: elem = getMeshDS()->AddFace(nodes[0], nodes[1], nodes[2], nodes[3],
1037                                       nodes[4], nodes[5], nodes[6], nodes[7],
1038                                       nodes[8] ); break;
1039   default: elem = getMeshDS()->AddPolygonalFace(nodes);
1040   }
1041
1042   // Update Python script
1043   TPythonDump() << "faceID = " << this << ".AddFace( " << IDsOfNodes << " )";
1044
1045   declareMeshModified( /*isReComputeSafe=*/false );
1046
1047   return elem ? elem->GetID() : 0;
1048
1049   SMESH_CATCH( SMESH::throwCorbaException );
1050   return 0;
1051 }
1052
1053 //=============================================================================
1054 /*!
1055  *  AddPolygonalFace
1056  */
1057 //=============================================================================
1058 CORBA::Long SMESH_MeshEditor_i::AddPolygonalFace (const SMESH::long_array & IDsOfNodes)
1059   throw (SALOME::SALOME_Exception)
1060 {
1061   SMESH_TRY;
1062   initData();
1063
1064   int NbNodes = IDsOfNodes.length();
1065   std::vector<const SMDS_MeshNode*> nodes (NbNodes);
1066   for (int i = 0; i < NbNodes; i++)
1067     nodes[i] = getMeshDS()->FindNode(IDsOfNodes[i]);
1068
1069   const SMDS_MeshElement* elem = getMeshDS()->AddPolygonalFace(nodes);
1070
1071   // Update Python script
1072   TPythonDump() <<"faceID = "<<this<<".AddPolygonalFace( "<<IDsOfNodes<<" )";
1073
1074   declareMeshModified( /*isReComputeSafe=*/false );
1075   return elem ? elem->GetID() : 0;
1076
1077   SMESH_CATCH( SMESH::throwCorbaException );
1078   return 0;
1079 }
1080
1081 //=============================================================================
1082 /*!
1083  * Create volume, either linear and quadratic (this is determed
1084  *  by number of given nodes)
1085  */
1086 //=============================================================================
1087
1088 CORBA::Long SMESH_MeshEditor_i::AddVolume(const SMESH::long_array & IDsOfNodes)
1089   throw (SALOME::SALOME_Exception)
1090 {
1091   SMESH_TRY;
1092   initData();
1093
1094   int NbNodes = IDsOfNodes.length();
1095   vector< const SMDS_MeshNode*> n(NbNodes);
1096   for(int i=0;i<NbNodes;i++)
1097     n[i]= getMeshDS()->FindNode(IDsOfNodes[i]);
1098
1099   SMDS_MeshElement* elem = 0;
1100   switch(NbNodes)
1101   {
1102   case 4 :elem = getMeshDS()->AddVolume(n[0],n[1],n[2],n[3]); break;
1103   case 5 :elem = getMeshDS()->AddVolume(n[0],n[1],n[2],n[3],n[4]); break;
1104   case 6 :elem = getMeshDS()->AddVolume(n[0],n[1],n[2],n[3],n[4],n[5]); break;
1105   case 8 :elem = getMeshDS()->AddVolume(n[0],n[1],n[2],n[3],n[4],n[5],n[6],n[7]); break;
1106   case 10:elem = getMeshDS()->AddVolume(n[0],n[1],n[2],n[3],n[4],n[5],
1107                                         n[6],n[7],n[8],n[9]);
1108     break;
1109   case 12:elem = getMeshDS()->AddVolume(n[0],n[1],n[2],n[3],n[4],n[5],
1110                                         n[6],n[7],n[8],n[9],n[10],n[11]);
1111     break;
1112   case 13:elem = getMeshDS()->AddVolume(n[0],n[1],n[2],n[3],n[4],n[5],n[6],
1113                                         n[7],n[8],n[9],n[10],n[11],n[12]);
1114     break;
1115   case 15:elem = getMeshDS()->AddVolume(n[0],n[1],n[2],n[3],n[4],n[5],n[6],n[7],n[8],
1116                                         n[9],n[10],n[11],n[12],n[13],n[14]);
1117     break;
1118   case 20:elem = getMeshDS()->AddVolume(n[0],n[1],n[2],n[3],n[4],n[5],n[6],n[7],
1119                                         n[8],n[9],n[10],n[11],n[12],n[13],n[14],
1120                                         n[15],n[16],n[17],n[18],n[19]);
1121     break;
1122   case 27:elem = getMeshDS()->AddVolume(n[0],n[1],n[2],n[3],n[4],n[5],n[6],n[7],
1123                                         n[8],n[9],n[10],n[11],n[12],n[13],n[14],
1124                                         n[15],n[16],n[17],n[18],n[19],
1125                                         n[20],n[21],n[22],n[23],n[24],n[25],n[26]);
1126     break;
1127   }
1128
1129   // Update Python script
1130   TPythonDump() << "volID = " << this << ".AddVolume( " << IDsOfNodes << " )";
1131
1132   declareMeshModified( /*isReComputeSafe=*/false );
1133   return elem ? elem->GetID() : 0;
1134
1135   SMESH_CATCH( SMESH::throwCorbaException );
1136   return 0;
1137 }
1138
1139 //=============================================================================
1140 /*!
1141  *  AddPolyhedralVolume
1142  */
1143 //=============================================================================
1144 CORBA::Long SMESH_MeshEditor_i::AddPolyhedralVolume (const SMESH::long_array & IDsOfNodes,
1145                                                      const SMESH::long_array & Quantities)
1146   throw (SALOME::SALOME_Exception)
1147 {
1148   SMESH_TRY;
1149   initData();
1150
1151   int NbNodes = IDsOfNodes.length();
1152   std::vector<const SMDS_MeshNode*> n (NbNodes);
1153   for (int i = 0; i < NbNodes; i++)
1154     {
1155       const SMDS_MeshNode* aNode = getMeshDS()->FindNode(IDsOfNodes[i]);
1156       if (!aNode) return 0;
1157       n[i] = aNode;
1158     }
1159
1160   int NbFaces = Quantities.length();
1161   std::vector<int> q (NbFaces);
1162   for (int j = 0; j < NbFaces; j++)
1163     q[j] = Quantities[j];
1164
1165   const SMDS_MeshElement* elem = getMeshDS()->AddPolyhedralVolume(n, q);
1166
1167   // Update Python script
1168   TPythonDump() << "volID = " << this << ".AddPolyhedralVolume( "
1169                 << IDsOfNodes << ", " << Quantities << " )";
1170
1171   declareMeshModified( /*isReComputeSafe=*/false );
1172   return elem ? elem->GetID() : 0;
1173
1174   SMESH_CATCH( SMESH::throwCorbaException );
1175   return 0;
1176 }
1177
1178 //=============================================================================
1179 /*!
1180  *  AddPolyhedralVolumeByFaces
1181  */
1182 //=============================================================================
1183
1184 CORBA::Long SMESH_MeshEditor_i::AddPolyhedralVolumeByFaces (const SMESH::long_array & IdsOfFaces)
1185   throw (SALOME::SALOME_Exception)
1186 {
1187   SMESH_TRY;
1188   initData();
1189
1190   int NbFaces = IdsOfFaces.length();
1191   std::vector<const SMDS_MeshNode*> poly_nodes;
1192   std::vector<int> quantities (NbFaces);
1193
1194   for (int i = 0; i < NbFaces; i++) {
1195     const SMDS_MeshElement* aFace = getMeshDS()->FindElement(IdsOfFaces[i]);
1196     quantities[i] = aFace->NbNodes();
1197
1198     SMDS_ElemIteratorPtr It = aFace->nodesIterator();
1199     while (It->more()) {
1200       poly_nodes.push_back(static_cast<const SMDS_MeshNode *>(It->next()));
1201     }
1202   }
1203
1204   const SMDS_MeshElement* elem = getMeshDS()->AddPolyhedralVolume(poly_nodes, quantities);
1205
1206   // Update Python script
1207   TPythonDump() << "volID = " << this << ".AddPolyhedralVolumeByFaces( "
1208                 << IdsOfFaces << " )";
1209
1210   declareMeshModified( /*isReComputeSafe=*/false );
1211   return elem ? elem->GetID() : 0;
1212
1213   SMESH_CATCH( SMESH::throwCorbaException );
1214   return 0;
1215 }
1216
1217 //=============================================================================
1218 //
1219 // \brief Create 0D elements on all nodes of the given object except those 
1220 //        nodes on which a 0D element already exists.
1221 //  \param theObject object on whose nodes 0D elements will be created.
1222 //  \param theGroupName optional name of a group to add 0D elements created
1223 //         and/or found on nodes of \a theObject.
1224 //  \return an object (a new group or a temporary SMESH_IDSource) holding
1225 //          ids of new and/or found 0D elements.
1226 //
1227 //=============================================================================
1228
1229 SMESH::SMESH_IDSource_ptr
1230 SMESH_MeshEditor_i::Create0DElementsOnAllNodes(SMESH::SMESH_IDSource_ptr theObject,
1231                                                const char*               theGroupName)
1232   throw (SALOME::SALOME_Exception)
1233 {
1234   SMESH_TRY;
1235   initData();
1236
1237   SMESH::SMESH_IDSource_var result;
1238   TPythonDump pyDump;
1239
1240   TIDSortedElemSet elements, elems0D;
1241   if ( idSourceToSet( theObject, getMeshDS(), elements, SMDSAbs_All, /*emptyIfIsMesh=*/1))
1242     getEditor().Create0DElementsOnAllNodes( elements, elems0D );
1243
1244   SMESH::long_array_var newElems = new SMESH::long_array;
1245   newElems->length( elems0D.size() );
1246   TIDSortedElemSet::iterator eIt = elems0D.begin();
1247   for ( size_t i = 0; i < elems0D.size(); ++i, ++eIt )
1248     newElems[ i ] = (*eIt)->GetID();
1249
1250   SMESH::SMESH_GroupBase_var groupToFill;
1251   if ( theGroupName && strlen( theGroupName ))
1252   {
1253     // Get existing group named theGroupName
1254     SMESH::ListOfGroups_var groups = myMesh_i->GetGroups();
1255     for (int i = 0, nbGroups = groups->length(); i < nbGroups; i++ ) {
1256       SMESH::SMESH_GroupBase_var group = groups[i];
1257       if ( !group->_is_nil() ) {
1258         CORBA::String_var name = group->GetName();
1259         if ( strcmp( name.in(), theGroupName ) == 0 && group->GetType() == SMESH::ELEM0D ) {
1260           groupToFill = group;
1261           break;
1262         }
1263       }
1264     }
1265     if ( groupToFill->_is_nil() )
1266       groupToFill = myMesh_i->CreateGroup( SMESH::ELEM0D, theGroupName );
1267     else if ( !SMESH::DownCast< SMESH_Group_i* > ( groupToFill ))
1268       groupToFill = myMesh_i->ConvertToStandalone( groupToFill );
1269   }
1270
1271   if ( SMESH_Group_i* group_i = SMESH::DownCast< SMESH_Group_i* > ( groupToFill ))
1272   {
1273     group_i->Add( newElems );
1274     result = SMESH::SMESH_IDSource::_narrow( groupToFill );
1275     pyDump << groupToFill;
1276   }
1277   else
1278   {
1279     result = MakeIDSource( newElems, SMESH::ELEM0D );
1280     pyDump << "elem0DIDs";
1281   }
1282
1283   pyDump << " = " << this << ".Create0DElementsOnAllNodes( "
1284          << theObject << ", '" << theGroupName << "' )";
1285
1286   return result._retn();
1287
1288   SMESH_CATCH( SMESH::throwCorbaException );
1289   return 0;
1290 }
1291
1292 //=============================================================================
1293 /*!
1294  * \brief Bind a node to a vertex
1295  * \param NodeID - node ID
1296  * \param VertexID - vertex ID available through GEOM_Object.GetSubShapeIndices()[0]
1297  * \retval boolean - false if NodeID or VertexID is invalid
1298  */
1299 //=============================================================================
1300
1301 void SMESH_MeshEditor_i::SetNodeOnVertex(CORBA::Long NodeID, CORBA::Long VertexID)
1302   throw (SALOME::SALOME_Exception)
1303 {
1304   SMESH_TRY;
1305
1306   SMESHDS_Mesh * mesh = getMeshDS();
1307   SMDS_MeshNode* node = const_cast<SMDS_MeshNode*>( mesh->FindNode(NodeID) );
1308   if ( !node )
1309     THROW_SALOME_CORBA_EXCEPTION("Invalid NodeID", SALOME::BAD_PARAM);
1310
1311   if ( mesh->MaxShapeIndex() < VertexID )
1312     THROW_SALOME_CORBA_EXCEPTION("Invalid VertexID", SALOME::BAD_PARAM);
1313
1314   TopoDS_Shape shape = mesh->IndexToShape( VertexID );
1315   if ( shape.ShapeType() != TopAbs_VERTEX )
1316     THROW_SALOME_CORBA_EXCEPTION("Invalid VertexID", SALOME::BAD_PARAM);
1317
1318   mesh->SetNodeOnVertex( node, VertexID );
1319
1320   myMesh->SetIsModified( true );
1321
1322   SMESH_CATCH( SMESH::throwCorbaException );
1323 }
1324
1325 //=============================================================================
1326 /*!
1327  * \brief Store node position on an edge
1328  * \param NodeID - node ID
1329  * \param EdgeID - edge ID available through GEOM_Object.GetSubShapeIndices()[0]
1330  * \param paramOnEdge - parameter on edge where the node is located
1331  * \retval boolean - false if any parameter is invalid
1332  */
1333 //=============================================================================
1334
1335 void SMESH_MeshEditor_i::SetNodeOnEdge(CORBA::Long NodeID, CORBA::Long EdgeID,
1336                                        CORBA::Double paramOnEdge)
1337   throw (SALOME::SALOME_Exception)
1338 {
1339   SMESH_TRY;
1340
1341   SMESHDS_Mesh * mesh = getMeshDS();
1342   SMDS_MeshNode* node = const_cast<SMDS_MeshNode*>( mesh->FindNode(NodeID) );
1343   if ( !node )
1344     THROW_SALOME_CORBA_EXCEPTION("Invalid NodeID", SALOME::BAD_PARAM);
1345
1346   if ( mesh->MaxShapeIndex() < EdgeID )
1347     THROW_SALOME_CORBA_EXCEPTION("Invalid EdgeID", SALOME::BAD_PARAM);
1348
1349   TopoDS_Shape shape = mesh->IndexToShape( EdgeID );
1350   if ( shape.ShapeType() != TopAbs_EDGE )
1351     THROW_SALOME_CORBA_EXCEPTION("Invalid EdgeID", SALOME::BAD_PARAM);
1352
1353   Standard_Real f,l;
1354   BRep_Tool::Range( TopoDS::Edge( shape ), f,l);
1355   if ( paramOnEdge < f || paramOnEdge > l )
1356     THROW_SALOME_CORBA_EXCEPTION("Invalid paramOnEdge", SALOME::BAD_PARAM);
1357
1358   mesh->SetNodeOnEdge( node, EdgeID, paramOnEdge );
1359
1360   myMesh->SetIsModified( true );
1361
1362   SMESH_CATCH( SMESH::throwCorbaException );
1363 }
1364
1365 //=============================================================================
1366 /*!
1367  * \brief Store node position on a face
1368  * \param NodeID - node ID
1369  * \param FaceID - face ID available through GEOM_Object.GetSubShapeIndices()[0]
1370  * \param u - U parameter on face where the node is located
1371  * \param v - V parameter on face where the node is located
1372  * \retval boolean - false if any parameter is invalid
1373  */
1374 //=============================================================================
1375
1376 void SMESH_MeshEditor_i::SetNodeOnFace(CORBA::Long NodeID, CORBA::Long FaceID,
1377                                        CORBA::Double u, CORBA::Double v)
1378   throw (SALOME::SALOME_Exception)
1379 {
1380   SMESH_TRY;
1381   SMESHDS_Mesh * mesh = getMeshDS();
1382   SMDS_MeshNode* node = const_cast<SMDS_MeshNode*>( mesh->FindNode(NodeID) );
1383   if ( !node )
1384     THROW_SALOME_CORBA_EXCEPTION("Invalid NodeID", SALOME::BAD_PARAM);
1385
1386   if ( mesh->MaxShapeIndex() < FaceID )
1387     THROW_SALOME_CORBA_EXCEPTION("Invalid FaceID", SALOME::BAD_PARAM);
1388
1389   TopoDS_Shape shape = mesh->IndexToShape( FaceID );
1390   if ( shape.ShapeType() != TopAbs_FACE )
1391     THROW_SALOME_CORBA_EXCEPTION("Invalid FaceID", SALOME::BAD_PARAM);
1392
1393   BRepAdaptor_Surface surf( TopoDS::Face( shape ));
1394   bool isOut = ( u < surf.FirstUParameter() ||
1395                  u > surf.LastUParameter()  ||
1396                  v < surf.FirstVParameter() ||
1397                  v > surf.LastVParameter() );
1398
1399   if ( isOut ) {
1400 #ifdef _DEBUG_
1401     MESSAGE ( "FACE " << FaceID << " (" << u << "," << v << ") out of "
1402               << " u( " <<  surf.FirstUParameter()
1403               << "," <<  surf.LastUParameter()
1404               << ") v( " <<  surf.FirstVParameter()
1405               << "," <<  surf.LastVParameter() << ")" );
1406 #endif
1407     THROW_SALOME_CORBA_EXCEPTION("Invalid UV", SALOME::BAD_PARAM);
1408   }
1409
1410   mesh->SetNodeOnFace( node, FaceID, u, v );
1411   myMesh->SetIsModified( true );
1412
1413   SMESH_CATCH( SMESH::throwCorbaException );
1414 }
1415
1416 //=============================================================================
1417 /*!
1418  * \brief Bind a node to a solid
1419  * \param NodeID - node ID
1420  * \param SolidID - vertex ID available through GEOM_Object.GetSubShapeIndices()[0]
1421  * \retval boolean - false if NodeID or SolidID is invalid
1422  */
1423 //=============================================================================
1424
1425 void SMESH_MeshEditor_i::SetNodeInVolume(CORBA::Long NodeID, CORBA::Long SolidID)
1426   throw (SALOME::SALOME_Exception)
1427 {
1428   SMESH_TRY;
1429   SMESHDS_Mesh * mesh = getMeshDS();
1430   SMDS_MeshNode* node = const_cast<SMDS_MeshNode*>( mesh->FindNode(NodeID) );
1431   if ( !node )
1432     THROW_SALOME_CORBA_EXCEPTION("Invalid NodeID", SALOME::BAD_PARAM);
1433
1434   if ( mesh->MaxShapeIndex() < SolidID )
1435     THROW_SALOME_CORBA_EXCEPTION("Invalid SolidID", SALOME::BAD_PARAM);
1436
1437   TopoDS_Shape shape = mesh->IndexToShape( SolidID );
1438   if ( shape.ShapeType() != TopAbs_SOLID &&
1439        shape.ShapeType() != TopAbs_SHELL)
1440     THROW_SALOME_CORBA_EXCEPTION("Invalid SolidID", SALOME::BAD_PARAM);
1441
1442   mesh->SetNodeInVolume( node, SolidID );
1443
1444   SMESH_CATCH( SMESH::throwCorbaException );
1445 }
1446
1447 //=============================================================================
1448 /*!
1449  * \brief Bind an element to a shape
1450  * \param ElementID - element ID
1451  * \param ShapeID - shape ID available through GEOM_Object.GetSubShapeIndices()[0]
1452  */
1453 //=============================================================================
1454
1455 void SMESH_MeshEditor_i::SetMeshElementOnShape(CORBA::Long ElementID,
1456                                                CORBA::Long ShapeID)
1457   throw (SALOME::SALOME_Exception)
1458 {
1459   SMESH_TRY;
1460   SMESHDS_Mesh * mesh = getMeshDS();
1461   SMDS_MeshElement* elem = const_cast<SMDS_MeshElement*>(mesh->FindElement(ElementID));
1462   if ( !elem )
1463     THROW_SALOME_CORBA_EXCEPTION("Invalid ElementID", SALOME::BAD_PARAM);
1464
1465   if ( mesh->MaxShapeIndex() < ShapeID || ShapeID < 1 )
1466     THROW_SALOME_CORBA_EXCEPTION("Invalid ShapeID", SALOME::BAD_PARAM);
1467
1468   TopoDS_Shape shape = mesh->IndexToShape( ShapeID );
1469   if ( shape.ShapeType() != TopAbs_EDGE &&
1470        shape.ShapeType() != TopAbs_FACE &&
1471        shape.ShapeType() != TopAbs_SOLID &&
1472        shape.ShapeType() != TopAbs_SHELL )
1473     THROW_SALOME_CORBA_EXCEPTION("Invalid shape type", SALOME::BAD_PARAM);
1474
1475   mesh->SetMeshElementOnShape( elem, ShapeID );
1476
1477   myMesh->SetIsModified( true );
1478
1479   SMESH_CATCH( SMESH::throwCorbaException );
1480 }
1481
1482 //=============================================================================
1483 /*!
1484  *
1485  */
1486 //=============================================================================
1487
1488 CORBA::Boolean SMESH_MeshEditor_i::InverseDiag(CORBA::Long NodeID1,
1489                                                CORBA::Long NodeID2)
1490   throw (SALOME::SALOME_Exception)
1491 {
1492   SMESH_TRY;
1493   initData();
1494
1495   const SMDS_MeshNode * n1 = getMeshDS()->FindNode( NodeID1 );
1496   const SMDS_MeshNode * n2 = getMeshDS()->FindNode( NodeID2 );
1497   if ( !n1 || !n2 )
1498     return false;
1499
1500   // Update Python script
1501   TPythonDump() << "isDone = " << this << ".InverseDiag( "
1502                 << NodeID1 << ", " << NodeID2 << " )";
1503
1504   int ret =  getEditor().InverseDiag ( n1, n2 );
1505
1506   declareMeshModified( /*isReComputeSafe=*/false );
1507   return ret;
1508
1509   SMESH_CATCH( SMESH::throwCorbaException );
1510   return 0;
1511 }
1512
1513 //=============================================================================
1514 /*!
1515  *
1516  */
1517 //=============================================================================
1518
1519 CORBA::Boolean SMESH_MeshEditor_i::DeleteDiag(CORBA::Long NodeID1,
1520                                               CORBA::Long NodeID2)
1521   throw (SALOME::SALOME_Exception)
1522 {
1523   SMESH_TRY;
1524   initData();
1525
1526   const SMDS_MeshNode * n1 = getMeshDS()->FindNode( NodeID1 );
1527   const SMDS_MeshNode * n2 = getMeshDS()->FindNode( NodeID2 );
1528   if ( !n1 || !n2 )
1529     return false;
1530
1531   // Update Python script
1532   TPythonDump() << "isDone = " << this << ".DeleteDiag( "
1533                 << NodeID1 << ", " << NodeID2 <<  " )";
1534
1535
1536   bool stat = getEditor().DeleteDiag ( n1, n2 );
1537
1538   declareMeshModified( /*isReComputeSafe=*/!stat );
1539
1540   return stat;
1541
1542   SMESH_CATCH( SMESH::throwCorbaException );
1543   return 0;
1544 }
1545
1546 //=============================================================================
1547 /*!
1548  *
1549  */
1550 //=============================================================================
1551
1552 CORBA::Boolean SMESH_MeshEditor_i::Reorient(const SMESH::long_array & IDsOfElements)
1553   throw (SALOME::SALOME_Exception)
1554 {
1555   SMESH_TRY;
1556   initData();
1557
1558   for (int i = 0; i < IDsOfElements.length(); i++)
1559   {
1560     CORBA::Long index = IDsOfElements[i];
1561     const SMDS_MeshElement * elem = getMeshDS()->FindElement(index);
1562     if ( elem )
1563       getEditor().Reorient( elem );
1564   }
1565   // Update Python script
1566   TPythonDump() << "isDone = " << this << ".Reorient( " << IDsOfElements << " )";
1567
1568   declareMeshModified( /*isReComputeSafe=*/ IDsOfElements.length() == 0 );
1569   return true;
1570
1571   SMESH_CATCH( SMESH::throwCorbaException );
1572   return 0;
1573 }
1574
1575 //=============================================================================
1576 /*!
1577  *
1578  */
1579 //=============================================================================
1580
1581 CORBA::Boolean SMESH_MeshEditor_i::ReorientObject(SMESH::SMESH_IDSource_ptr theObject)
1582   throw (SALOME::SALOME_Exception)
1583 {
1584   SMESH_TRY;
1585   initData();
1586
1587   TPythonDump aTPythonDump; // suppress dump in Reorient()
1588
1589   prepareIdSource( theObject );
1590
1591   SMESH::long_array_var anElementsId = theObject->GetIDs();
1592   CORBA::Boolean isDone = Reorient(anElementsId);
1593
1594   // Update Python script
1595   aTPythonDump << "isDone = " << this << ".ReorientObject( " << theObject << " )";
1596
1597   declareMeshModified( /*isReComputeSafe=*/ anElementsId->length() == 0 );
1598   return isDone;
1599
1600   SMESH_CATCH( SMESH::throwCorbaException );
1601   return 0;
1602 }
1603
1604 //=======================================================================
1605 //function : Reorient2D
1606 //purpose  : Reorient faces contained in \a the2Dgroup.
1607 //           the2Dgroup   - the mesh or its part to reorient
1608 //           theDirection - desired direction of normal of \a theFace
1609 //           theFace      - ID of face whose orientation is checked.
1610 //           It can be < 1 then \a thePoint is used to find a face.
1611 //           thePoint     - is used to find a face if \a theFace < 1.
1612 //           return number of reoriented elements.
1613 //=======================================================================
1614
1615 CORBA::Long SMESH_MeshEditor_i::Reorient2D(SMESH::SMESH_IDSource_ptr the2Dgroup,
1616                                            const SMESH::DirStruct&   theDirection,
1617                                            CORBA::Long               theFace,
1618                                            const SMESH::PointStruct& thePoint)
1619   throw (SALOME::SALOME_Exception)
1620 {
1621   SMESH_TRY;
1622   initData(/*deleteSearchers=*/false);
1623
1624   TIDSortedElemSet elements;
1625   IDSource_Error error;
1626   idSourceToSet( the2Dgroup, getMeshDS(), elements, SMDSAbs_Face, /*emptyIfIsMesh=*/1, &error );
1627   if ( error == IDSource_EMPTY )
1628     return 0;
1629   if ( error == IDSource_INVALID )
1630     THROW_SALOME_CORBA_EXCEPTION("No faces in given group", SALOME::BAD_PARAM);
1631
1632
1633   const SMDS_MeshElement* face = 0;
1634   if ( theFace > 0 )
1635   {
1636     face = getMeshDS()->FindElement( theFace );
1637     if ( !face )
1638       THROW_SALOME_CORBA_EXCEPTION("Inexistent face given", SALOME::BAD_PARAM);
1639     if ( face->GetType() != SMDSAbs_Face )
1640       THROW_SALOME_CORBA_EXCEPTION("Wrong element type", SALOME::BAD_PARAM);
1641   }
1642   else
1643   {
1644     // create theElementSearcher if needed
1645     theSearchersDeleter.Set( myMesh, getPartIOR( the2Dgroup, SMESH::FACE ));
1646     if ( !theElementSearcher )
1647     {
1648       if ( elements.empty() ) // search in the whole mesh
1649       {
1650         if ( myMesh->NbFaces() == 0 )
1651           THROW_SALOME_CORBA_EXCEPTION("No faces in the mesh", SALOME::BAD_PARAM);
1652
1653         theElementSearcher = SMESH_MeshAlgos::GetElementSearcher( *getMeshDS() );
1654       }
1655       else
1656       {
1657         typedef SMDS_SetIterator<const SMDS_MeshElement*, TIDSortedElemSet::const_iterator > TIter;
1658         SMDS_ElemIteratorPtr elemsIt( new TIter( elements.begin(), elements.end() ));
1659
1660         theElementSearcher = SMESH_MeshAlgos::GetElementSearcher( *getMeshDS(), elemsIt);
1661       }
1662     }
1663     // find a face
1664     gp_Pnt p( thePoint.x, thePoint.y, thePoint.z );
1665     face = theElementSearcher->FindClosestTo( p, SMDSAbs_Face );
1666
1667     if ( !face )
1668       THROW_SALOME_CORBA_EXCEPTION("No face found by point", SALOME::INTERNAL_ERROR );
1669     if ( !elements.empty() && !elements.count( face ))
1670       THROW_SALOME_CORBA_EXCEPTION("Found face is not in the group", SALOME::BAD_PARAM );
1671   }
1672
1673   const SMESH::PointStruct * P = &theDirection.PS;
1674   gp_Vec dirVec( P->x, P->y, P->z );
1675   if ( dirVec.Magnitude() < std::numeric_limits< double >::min() )
1676     THROW_SALOME_CORBA_EXCEPTION("Zero size vector", SALOME::BAD_PARAM);
1677
1678   int nbReori = getEditor().Reorient2D( elements, dirVec, face );
1679
1680   if ( nbReori ) {
1681     declareMeshModified( /*isReComputeSafe=*/false );
1682   }
1683   TPythonDump() << this << ".Reorient2D( "
1684                 << the2Dgroup << ", "
1685                 << theDirection << ", "
1686                 << theFace << ", "
1687                 << thePoint << " )";
1688
1689   return nbReori;
1690
1691   SMESH_CATCH( SMESH::throwCorbaException );
1692   return 0;
1693 }
1694
1695 //=======================================================================
1696 //function : Reorient2DBy3D
1697 //purpose  : Reorient faces basing on orientation of adjacent volumes.
1698 //=======================================================================
1699
1700 CORBA::Long SMESH_MeshEditor_i::Reorient2DBy3D(const SMESH::ListOfIDSources& faceGroups,
1701                                                SMESH::SMESH_IDSource_ptr     volumeGroup,
1702                                                CORBA::Boolean                outsideNormal)
1703   throw (SALOME::SALOME_Exception)
1704 {
1705   SMESH_TRY;
1706   initData();
1707
1708   TIDSortedElemSet volumes;
1709   IDSource_Error volsError;
1710   idSourceToSet( volumeGroup, getMeshDS(), volumes, SMDSAbs_Volume, /*emptyIfMesh=*/1, &volsError);
1711
1712   int nbReori = 0;
1713   for ( size_t i = 0; i < faceGroups.length(); ++i )
1714   {
1715     SMESH::SMESH_IDSource_ptr faceGrp = faceGroups[i].in();
1716
1717     TIDSortedElemSet faces;
1718     IDSource_Error error;
1719     idSourceToSet( faceGrp, getMeshDS(), faces, SMDSAbs_Face, /*emptyIfIsMesh=*/1, &error );
1720     if ( error == IDSource_INVALID && faceGroups.length() == 1 )
1721       THROW_SALOME_CORBA_EXCEPTION("No faces in a given object", SALOME::BAD_PARAM);
1722     if ( error == IDSource_OK && volsError != IDSource_OK )
1723       THROW_SALOME_CORBA_EXCEPTION("No volumes in a given object", SALOME::BAD_PARAM);
1724
1725     nbReori += getEditor().Reorient2DBy3D( faces, volumes, outsideNormal );
1726
1727     if ( error != IDSource_EMPTY && faces.empty() ) // all faces in the mesh treated
1728       break;
1729   }
1730
1731   if ( nbReori ) {
1732     declareMeshModified( /*isReComputeSafe=*/false );
1733   }
1734   TPythonDump() << this << ".Reorient2DBy3D( "
1735                 << faceGroups << ", "
1736                 << volumeGroup << ", "
1737                 << outsideNormal << " )";
1738
1739   return nbReori;
1740
1741   SMESH_CATCH( SMESH::throwCorbaException );
1742   return 0;
1743 }
1744
1745 //=============================================================================
1746 /*!
1747  * \brief Fuse neighbour triangles into quadrangles.
1748  */
1749 //=============================================================================
1750
1751 CORBA::Boolean SMESH_MeshEditor_i::TriToQuad (const SMESH::long_array &   IDsOfElements,
1752                                               SMESH::NumericalFunctor_ptr Criterion,
1753                                               CORBA::Double               MaxAngle)
1754   throw (SALOME::SALOME_Exception)
1755 {
1756   SMESH_TRY;
1757   initData();
1758
1759   SMESHDS_Mesh* aMesh = getMeshDS();
1760   TIDSortedElemSet faces,copyFaces;
1761   SMDS_MeshElement::GeomFilter triaFilter(SMDSGeom_TRIANGLE);
1762   arrayToSet(IDsOfElements, aMesh, faces, SMDSAbs_Face, & triaFilter);
1763   TIDSortedElemSet* workElements = & faces;
1764
1765   if ( myIsPreviewMode ) {
1766     SMDSAbs_ElementType select =  SMDSAbs_Face;
1767     getPreviewMesh( SMDSAbs_Face )->Copy( faces, copyFaces, select );
1768     workElements = & copyFaces;
1769   }
1770
1771   SMESH::NumericalFunctor_i* aNumericalFunctor =
1772     dynamic_cast<SMESH::NumericalFunctor_i*>( SMESH_Gen_i::GetServant( Criterion ).in() );
1773   SMESH::Controls::NumericalFunctorPtr aCrit;
1774   if ( !aNumericalFunctor )
1775     aCrit.reset( new SMESH::Controls::MaxElementLength2D() );
1776   else
1777     aCrit = aNumericalFunctor->GetNumericalFunctor();
1778
1779   if ( !myIsPreviewMode ) {
1780     // Update Python script
1781     TPythonDump() << "isDone = " << this << ".TriToQuad( "
1782                   << IDsOfElements << ", " << aNumericalFunctor << ", " << TVar( MaxAngle ) << " )";
1783   }
1784
1785   bool stat = getEditor().TriToQuad( *workElements, aCrit, MaxAngle );
1786
1787   declareMeshModified( /*isReComputeSafe=*/!stat );
1788   return stat;
1789
1790   SMESH_CATCH( SMESH::throwCorbaException );
1791   return 0;
1792 }
1793
1794 //=============================================================================
1795 /*!
1796  * \brief Fuse neighbour triangles into quadrangles.
1797  */
1798 //=============================================================================
1799
1800 CORBA::Boolean SMESH_MeshEditor_i::TriToQuadObject (SMESH::SMESH_IDSource_ptr   theObject,
1801                                                     SMESH::NumericalFunctor_ptr Criterion,
1802                                                     CORBA::Double               MaxAngle)
1803   throw (SALOME::SALOME_Exception)
1804 {
1805   SMESH_TRY;
1806   initData();
1807
1808   TPythonDump aTPythonDump;  // suppress dump in TriToQuad()
1809
1810   prepareIdSource( theObject );
1811   SMESH::long_array_var anElementsId = theObject->GetIDs();
1812   CORBA::Boolean isDone = TriToQuad(anElementsId, Criterion, MaxAngle);
1813
1814   if ( !myIsPreviewMode ) {
1815     SMESH::NumericalFunctor_i* aNumericalFunctor =
1816       SMESH::DownCast<SMESH::NumericalFunctor_i*>( Criterion );
1817
1818     // Update Python script
1819     aTPythonDump << "isDone = " << this << ".TriToQuadObject("
1820                  << theObject << ", " << aNumericalFunctor << ", " << TVar( MaxAngle ) << " )";
1821   }
1822
1823   return isDone;
1824
1825   SMESH_CATCH( SMESH::throwCorbaException );
1826   return 0;
1827 }
1828
1829 //=============================================================================
1830 /*!
1831  * \brief Split quadrangles into triangles.
1832  */
1833 //=============================================================================
1834
1835 CORBA::Boolean SMESH_MeshEditor_i::QuadToTri (const SMESH::long_array &   IDsOfElements,
1836                                               SMESH::NumericalFunctor_ptr Criterion)
1837   throw (SALOME::SALOME_Exception)
1838 {
1839   SMESH_TRY;
1840   initData();
1841
1842   SMESHDS_Mesh* aMesh = getMeshDS();
1843   TIDSortedElemSet faces;
1844   arrayToSet(IDsOfElements, aMesh, faces, SMDSAbs_Face);
1845
1846   SMESH::NumericalFunctor_i* aNumericalFunctor =
1847     dynamic_cast<SMESH::NumericalFunctor_i*>( SMESH_Gen_i::GetServant( Criterion ).in() );
1848   SMESH::Controls::NumericalFunctorPtr aCrit;
1849   if ( !aNumericalFunctor )
1850     aCrit.reset( new SMESH::Controls::AspectRatio() );
1851   else
1852     aCrit = aNumericalFunctor->GetNumericalFunctor();
1853
1854
1855   // Update Python script
1856   TPythonDump() << "isDone = " << this << ".QuadToTri( " << IDsOfElements << ", " << aNumericalFunctor << " )";
1857
1858   CORBA::Boolean stat = getEditor().QuadToTri( faces, aCrit );
1859
1860   declareMeshModified( /*isReComputeSafe=*/false );
1861   return stat;
1862
1863   SMESH_CATCH( SMESH::throwCorbaException );
1864   return 0;
1865 }
1866
1867 //=============================================================================
1868 /*!
1869  * \brief Split quadrangles into triangles.
1870  */
1871 //=============================================================================
1872
1873 CORBA::Boolean SMESH_MeshEditor_i::QuadToTriObject (SMESH::SMESH_IDSource_ptr   theObject,
1874                                                     SMESH::NumericalFunctor_ptr Criterion)
1875   throw (SALOME::SALOME_Exception)
1876 {
1877   SMESH_TRY;
1878   initData();
1879
1880   TPythonDump aTPythonDump;  // suppress dump in QuadToTri()
1881
1882   prepareIdSource( theObject );
1883   SMESH::long_array_var anElementsId = theObject->GetIDs();
1884   CORBA::Boolean isDone = QuadToTri(anElementsId, Criterion);
1885
1886   SMESH::NumericalFunctor_i* aNumericalFunctor =
1887     SMESH::DownCast<SMESH::NumericalFunctor_i*>( Criterion );
1888
1889   // Update Python script
1890   aTPythonDump << "isDone = " << this << ".QuadToTriObject( " << theObject << ", " << aNumericalFunctor << " )";
1891
1892   declareMeshModified( /*isReComputeSafe=*/false );
1893   return isDone;
1894
1895   SMESH_CATCH( SMESH::throwCorbaException );
1896   return 0;
1897 }
1898
1899 //================================================================================
1900 /*!
1901  * \brief Split each of quadrangles into 4 triangles.
1902  *  \param [in] theObject - theQuads Container of quadrangles to split.
1903  */
1904 //================================================================================
1905
1906 void SMESH_MeshEditor_i::QuadTo4Tri (SMESH::SMESH_IDSource_ptr theObject)
1907   throw (SALOME::SALOME_Exception)
1908 {
1909   SMESH_TRY;
1910   initData();
1911
1912   TIDSortedElemSet faces;
1913   if ( !idSourceToSet( theObject, getMeshDS(), faces, SMDSAbs_Face, /*emptyIfIsMesh=*/true ) &&
1914        faces.empty() )
1915     THROW_SALOME_CORBA_EXCEPTION("No faces given", SALOME::BAD_PARAM);
1916
1917   getEditor().QuadTo4Tri( faces );
1918   TPythonDump() << this << ".QuadTo4Tri( " << theObject << " )";
1919
1920   SMESH_CATCH( SMESH::throwCorbaException );
1921 }
1922
1923 //=============================================================================
1924 /*!
1925  * \brief Split quadrangles into triangles.
1926  */
1927 //=============================================================================
1928
1929 CORBA::Boolean SMESH_MeshEditor_i::SplitQuad (const SMESH::long_array & IDsOfElements,
1930                                               CORBA::Boolean            Diag13)
1931   throw (SALOME::SALOME_Exception)
1932 {
1933   SMESH_TRY;
1934   initData();
1935
1936   SMESHDS_Mesh* aMesh = getMeshDS();
1937   TIDSortedElemSet faces;
1938   arrayToSet(IDsOfElements, aMesh, faces, SMDSAbs_Face);
1939
1940   // Update Python script
1941   TPythonDump() << "isDone = " << this << ".SplitQuad( "
1942                 << IDsOfElements << ", " << Diag13 << " )";
1943
1944   CORBA::Boolean stat = getEditor().QuadToTri( faces, Diag13 );
1945
1946   declareMeshModified( /*isReComputeSafe=*/ !stat );
1947   return stat;
1948
1949   SMESH_CATCH( SMESH::throwCorbaException );
1950   return 0;
1951 }
1952
1953 //=============================================================================
1954 /*!
1955  * \brief Split quadrangles into triangles.
1956  */
1957 //=============================================================================
1958
1959 CORBA::Boolean SMESH_MeshEditor_i::SplitQuadObject (SMESH::SMESH_IDSource_ptr theObject,
1960                                                     CORBA::Boolean            Diag13)
1961   throw (SALOME::SALOME_Exception)
1962 {
1963   SMESH_TRY;
1964   initData();
1965
1966   TPythonDump aTPythonDump;  // suppress dump in SplitQuad()
1967
1968   prepareIdSource( theObject );
1969   SMESH::long_array_var anElementsId = theObject->GetIDs();
1970   CORBA::Boolean isDone = SplitQuad(anElementsId, Diag13);
1971
1972   // Update Python script
1973   aTPythonDump << "isDone = " << this << ".SplitQuadObject( "
1974                << theObject << ", " << Diag13 << " )";
1975
1976   declareMeshModified( /*isReComputeSafe=*/!isDone );
1977   return isDone;
1978
1979   SMESH_CATCH( SMESH::throwCorbaException );
1980   return 0;
1981 }
1982
1983
1984 //=============================================================================
1985 /*!
1986  * Find better splitting of the given quadrangle.
1987  *  \param IDOfQuad  ID of the quadrangle to be splitted.
1988  *  \param Criterion A criterion to choose a diagonal for splitting.
1989  *  \return 1 if 1-3 diagonal is better, 2 if 2-4
1990  *          diagonal is better, 0 if error occurs.
1991  */
1992 //=============================================================================
1993
1994 CORBA::Long SMESH_MeshEditor_i::BestSplit (CORBA::Long                 IDOfQuad,
1995                                            SMESH::NumericalFunctor_ptr Criterion)
1996   throw (SALOME::SALOME_Exception)
1997 {
1998   SMESH_TRY;
1999   initData();
2000
2001   const SMDS_MeshElement* quad = getMeshDS()->FindElement(IDOfQuad);
2002   if (quad && quad->GetType() == SMDSAbs_Face && quad->NbNodes() == 4)
2003   {
2004     SMESH::NumericalFunctor_i* aNumericalFunctor =
2005       dynamic_cast<SMESH::NumericalFunctor_i*>(SMESH_Gen_i::GetServant(Criterion).in());
2006     SMESH::Controls::NumericalFunctorPtr aCrit;
2007     if (aNumericalFunctor)
2008       aCrit = aNumericalFunctor->GetNumericalFunctor();
2009     else
2010       aCrit.reset(new SMESH::Controls::AspectRatio());
2011
2012     int id = getEditor().BestSplit(quad, aCrit);
2013     declareMeshModified( /*isReComputeSafe=*/ id < 1 );
2014     return id;
2015   }
2016
2017   SMESH_CATCH( SMESH::throwCorbaException );
2018   return 0;
2019 }
2020
2021 //================================================================================
2022 /*!
2023  * \brief Split volumic elements into tetrahedrons
2024  */
2025 //================================================================================
2026
2027 void SMESH_MeshEditor_i::SplitVolumesIntoTetra (SMESH::SMESH_IDSource_ptr elems,
2028                                                 CORBA::Short              methodFlags)
2029   throw (SALOME::SALOME_Exception)
2030 {
2031   SMESH_TRY;
2032   initData();
2033
2034   ::SMESH_MeshEditor::TFacetOfElem elemSet;
2035   const int noneFacet = -1;
2036   SMDS_ElemIteratorPtr volIt = myMesh_i->GetElements( elems, SMESH::VOLUME );
2037   while( volIt->more() )
2038     elemSet.insert( elemSet.end(), make_pair( volIt->next(), noneFacet ));
2039
2040   getEditor().SplitVolumes( elemSet, int( methodFlags ));
2041   declareMeshModified( /*isReComputeSafe=*/true ); // it does not influence Compute()
2042
2043   TPythonDump() << this << ".SplitVolumesIntoTetra( "
2044                 << elems << ", " << methodFlags << " )";
2045
2046   SMESH_CATCH( SMESH::throwCorbaException );
2047 }
2048
2049 //================================================================================
2050 /*!
2051  * \brief Split hexahedra into triangular prisms
2052  *  \param elems - elements to split
2053  *  \param facetToSplitNormal - normal used to find a facet of hexahedron
2054  *         to split into triangles
2055  *  \param methodFlags - flags passing splitting method:
2056  *         1 - split the hexahedron into 2 prisms
2057  *         2 - split the hexahedron into 4 prisms
2058  */
2059 //================================================================================
2060
2061 void SMESH_MeshEditor_i::SplitHexahedraIntoPrisms (SMESH::SMESH_IDSource_ptr  elems,
2062                                                    const SMESH::PointStruct & startHexPoint,
2063                                                    const SMESH::DirStruct&    facetToSplitNormal,
2064                                                    CORBA::Short               methodFlags,
2065                                                    CORBA::Boolean             allDomains)
2066   throw (SALOME::SALOME_Exception)
2067 {
2068   SMESH_TRY;
2069   initData();
2070   prepareIdSource( elems );
2071
2072   gp_Ax1 facetNorm( gp_Pnt( startHexPoint.x,
2073                             startHexPoint.y,
2074                             startHexPoint.z ),
2075                     gp_Dir( facetToSplitNormal.PS.x,
2076                             facetToSplitNormal.PS.y,
2077                             facetToSplitNormal.PS.z ));
2078   TIDSortedElemSet elemSet;
2079   SMESH::long_array_var anElementsId = elems->GetIDs();
2080   SMDS_MeshElement::GeomFilter filter( SMDSGeom_HEXA );
2081   arrayToSet( anElementsId, getMeshDS(), elemSet, SMDSAbs_Volume, &filter );
2082
2083   ::SMESH_MeshEditor::TFacetOfElem elemFacets;
2084   while ( !elemSet.empty() )
2085   {
2086     getEditor().GetHexaFacetsToSplit( elemSet, facetNorm, elemFacets );
2087     if ( !allDomains )
2088       break;
2089
2090     ::SMESH_MeshEditor::TFacetOfElem::iterator ef = elemFacets.begin();
2091     for ( ; ef != elemFacets.end(); ++ef )
2092       elemSet.erase( ef->first );
2093   }
2094
2095   if ( methodFlags == 2 )
2096     methodFlags = int( ::SMESH_MeshEditor::HEXA_TO_4_PRISMS );
2097   else
2098     methodFlags = int( ::SMESH_MeshEditor::HEXA_TO_2_PRISMS );
2099
2100   getEditor().SplitVolumes( elemFacets, int( methodFlags ));
2101   declareMeshModified( /*isReComputeSafe=*/true ); // it does not influence Compute()
2102
2103   TPythonDump() << this << ".SplitHexahedraIntoPrisms( "
2104                 << elems << ", "
2105                 << startHexPoint << ", "
2106                 << facetToSplitNormal<< ", "
2107                 << methodFlags<< ", "
2108                 << allDomains << " )";
2109
2110   SMESH_CATCH( SMESH::throwCorbaException );
2111 }
2112
2113 //=======================================================================
2114 //function : Smooth
2115 //purpose  :
2116 //=======================================================================
2117
2118 CORBA::Boolean
2119 SMESH_MeshEditor_i::Smooth(const SMESH::long_array &              IDsOfElements,
2120                            const SMESH::long_array &              IDsOfFixedNodes,
2121                            CORBA::Long                            MaxNbOfIterations,
2122                            CORBA::Double                          MaxAspectRatio,
2123                            SMESH::SMESH_MeshEditor::Smooth_Method Method)
2124   throw (SALOME::SALOME_Exception)
2125 {
2126   return smooth( IDsOfElements, IDsOfFixedNodes, MaxNbOfIterations,
2127                  MaxAspectRatio, Method, false );
2128 }
2129
2130
2131 //=======================================================================
2132 //function : SmoothParametric
2133 //purpose  :
2134 //=======================================================================
2135
2136 CORBA::Boolean
2137 SMESH_MeshEditor_i::SmoothParametric(const SMESH::long_array &              IDsOfElements,
2138                                      const SMESH::long_array &              IDsOfFixedNodes,
2139                                      CORBA::Long                            MaxNbOfIterations,
2140                                      CORBA::Double                          MaxAspectRatio,
2141                                      SMESH::SMESH_MeshEditor::Smooth_Method Method)
2142   throw (SALOME::SALOME_Exception)
2143 {
2144   return smooth( IDsOfElements, IDsOfFixedNodes, MaxNbOfIterations,
2145                  MaxAspectRatio, Method, true );
2146 }
2147
2148
2149 //=======================================================================
2150 //function : SmoothObject
2151 //purpose  :
2152 //=======================================================================
2153
2154 CORBA::Boolean
2155 SMESH_MeshEditor_i::SmoothObject(SMESH::SMESH_IDSource_ptr              theObject,
2156                                  const SMESH::long_array &              IDsOfFixedNodes,
2157                                  CORBA::Long                            MaxNbOfIterations,
2158                                  CORBA::Double                          MaxAspectRatio,
2159                                  SMESH::SMESH_MeshEditor::Smooth_Method Method)
2160   throw (SALOME::SALOME_Exception)
2161 {
2162   return smoothObject (theObject, IDsOfFixedNodes, MaxNbOfIterations,
2163                        MaxAspectRatio, Method, false);
2164 }
2165
2166
2167 //=======================================================================
2168 //function : SmoothParametricObject
2169 //purpose  :
2170 //=======================================================================
2171
2172 CORBA::Boolean
2173 SMESH_MeshEditor_i::SmoothParametricObject(SMESH::SMESH_IDSource_ptr              theObject,
2174                                            const SMESH::long_array &              IDsOfFixedNodes,
2175                                            CORBA::Long                            MaxNbOfIterations,
2176                                            CORBA::Double                          MaxAspectRatio,
2177                                            SMESH::SMESH_MeshEditor::Smooth_Method Method)
2178   throw (SALOME::SALOME_Exception)
2179 {
2180   return smoothObject (theObject, IDsOfFixedNodes, MaxNbOfIterations,
2181                        MaxAspectRatio, Method, true);
2182 }
2183
2184
2185 //=============================================================================
2186 /*!
2187  *
2188  */
2189 //=============================================================================
2190
2191 CORBA::Boolean
2192 SMESH_MeshEditor_i::smooth(const SMESH::long_array &              IDsOfElements,
2193                            const SMESH::long_array &              IDsOfFixedNodes,
2194                            CORBA::Long                            MaxNbOfIterations,
2195                            CORBA::Double                          MaxAspectRatio,
2196                            SMESH::SMESH_MeshEditor::Smooth_Method Method,
2197                            bool                                   IsParametric)
2198   throw (SALOME::SALOME_Exception)
2199 {
2200   SMESH_TRY;
2201   initData();
2202
2203   SMESHDS_Mesh* aMesh = getMeshDS();
2204
2205   TIDSortedElemSet elements;
2206   arrayToSet(IDsOfElements, aMesh, elements, SMDSAbs_Face);
2207
2208   set<const SMDS_MeshNode*> fixedNodes;
2209   for (int i = 0; i < IDsOfFixedNodes.length(); i++) {
2210     CORBA::Long index = IDsOfFixedNodes[i];
2211     const SMDS_MeshNode * node = aMesh->FindNode(index);
2212     if ( node )
2213       fixedNodes.insert( node );
2214   }
2215   ::SMESH_MeshEditor::SmoothMethod method = ::SMESH_MeshEditor::LAPLACIAN;
2216   if ( Method != SMESH::SMESH_MeshEditor::LAPLACIAN_SMOOTH )
2217     method = ::SMESH_MeshEditor::CENTROIDAL;
2218
2219   getEditor().Smooth(elements, fixedNodes, method,
2220                   MaxNbOfIterations, MaxAspectRatio, IsParametric );
2221
2222   declareMeshModified( /*isReComputeSafe=*/true ); // does not prevent re-compute
2223
2224   // Update Python script
2225   TPythonDump() << "isDone = " << this << "."
2226                 << (IsParametric ? "SmoothParametric( " : "Smooth( ")
2227                 << IDsOfElements << ", "     << IDsOfFixedNodes << ", "
2228                 << TVar( MaxNbOfIterations ) << ", " << TVar( MaxAspectRatio ) << ", "
2229                 << "SMESH.SMESH_MeshEditor."
2230                 << ( Method == SMESH::SMESH_MeshEditor::CENTROIDAL_SMOOTH ?
2231                      "CENTROIDAL_SMOOTH )" : "LAPLACIAN_SMOOTH )");
2232
2233   return true;
2234
2235   SMESH_CATCH( SMESH::throwCorbaException );
2236   return 0;
2237 }
2238
2239 //=============================================================================
2240 /*!
2241  *
2242  */
2243 //=============================================================================
2244
2245 CORBA::Boolean
2246 SMESH_MeshEditor_i::smoothObject(SMESH::SMESH_IDSource_ptr              theObject,
2247                                  const SMESH::long_array &              IDsOfFixedNodes,
2248                                  CORBA::Long                            MaxNbOfIterations,
2249                                  CORBA::Double                          MaxAspectRatio,
2250                                  SMESH::SMESH_MeshEditor::Smooth_Method Method,
2251                                  bool                                   IsParametric)
2252   throw (SALOME::SALOME_Exception)
2253 {
2254   SMESH_TRY;
2255   initData();
2256
2257   TPythonDump aTPythonDump;  // suppress dump in smooth()
2258
2259   prepareIdSource( theObject );
2260   SMESH::long_array_var anElementsId = theObject->GetIDs();
2261   CORBA::Boolean isDone = smooth (anElementsId, IDsOfFixedNodes, MaxNbOfIterations,
2262                                   MaxAspectRatio, Method, IsParametric);
2263
2264   // Update Python script
2265   aTPythonDump << "isDone = " << this << "."
2266                << (IsParametric ? "SmoothParametricObject( " : "SmoothObject( ")
2267                << theObject << ", " << IDsOfFixedNodes << ", "
2268                << TVar( MaxNbOfIterations ) << ", " << TVar( MaxAspectRatio ) << ", "
2269                << "SMESH.SMESH_MeshEditor."
2270                << ( Method == SMESH::SMESH_MeshEditor::CENTROIDAL_SMOOTH ?
2271                     "CENTROIDAL_SMOOTH )" : "LAPLACIAN_SMOOTH )");
2272
2273   return isDone;
2274
2275   SMESH_CATCH( SMESH::throwCorbaException );
2276   return 0;
2277 }
2278
2279 //=============================================================================
2280 /*!
2281  *
2282  */
2283 //=============================================================================
2284
2285 void SMESH_MeshEditor_i::RenumberNodes()
2286   throw (SALOME::SALOME_Exception)
2287 {
2288   SMESH_TRY;
2289   // Update Python script
2290   TPythonDump() << this << ".RenumberNodes()";
2291
2292   getMeshDS()->Renumber( true );
2293
2294   SMESH_CATCH( SMESH::throwCorbaException );
2295 }
2296
2297 //=============================================================================
2298 /*!
2299  *
2300  */
2301 //=============================================================================
2302
2303 void SMESH_MeshEditor_i::RenumberElements()
2304   throw (SALOME::SALOME_Exception)
2305 {
2306   SMESH_TRY;
2307   // Update Python script
2308   TPythonDump() << this << ".RenumberElements()";
2309
2310   getMeshDS()->Renumber( false );
2311
2312   SMESH_CATCH( SMESH::throwCorbaException );
2313 }
2314
2315 //=======================================================================
2316 /*!
2317  * \brief Return groups by their IDs
2318  */
2319 //=======================================================================
2320
2321 SMESH::ListOfGroups* SMESH_MeshEditor_i::getGroups(const std::list<int>* groupIDs)
2322   throw (SALOME::SALOME_Exception)
2323 {
2324   SMESH_TRY;
2325   if ( !groupIDs )
2326     return 0;
2327   myMesh_i->CreateGroupServants();
2328   return myMesh_i->GetGroups( *groupIDs );
2329
2330   SMESH_CATCH( SMESH::throwCorbaException );
2331   return 0;
2332 }
2333
2334 //=======================================================================
2335 //function : RotationSweepObjects
2336 //purpose  :
2337 //=======================================================================
2338
2339 SMESH::ListOfGroups*
2340 SMESH_MeshEditor_i::RotationSweepObjects(const SMESH::ListOfIDSources & theNodes,
2341                                          const SMESH::ListOfIDSources & theEdges,
2342                                          const SMESH::ListOfIDSources & theFaces,
2343                                          const SMESH::AxisStruct &      theAxis,
2344                                          CORBA::Double                  theAngleInRadians,
2345                                          CORBA::Long                    theNbOfSteps,
2346                                          CORBA::Double                  theTolerance,
2347                                          const bool                     theMakeGroups)
2348   throw (SALOME::SALOME_Exception)
2349 {
2350   SMESH_TRY;
2351   initData();
2352
2353   TIDSortedElemSet elemsNodes[2];
2354   for ( int i = 0, nb = theNodes.length(); i < nb; ++i ) {
2355     SMDS_ElemIteratorPtr nIt = myMesh_i->GetElements( theNodes[i], SMESH::NODE );
2356     while ( nIt->more() ) elemsNodes[1].insert( nIt->next() );
2357   }
2358   for ( int i = 0, nb = theEdges.length(); i < nb; ++i )
2359     idSourceToSet( theEdges[i], getMeshDS(), elemsNodes[0], SMDSAbs_Edge );
2360   for ( int i = 0, nb = theFaces.length(); i < nb; ++i )
2361     idSourceToSet( theFaces[i], getMeshDS(), elemsNodes[0], SMDSAbs_Face );
2362
2363   TIDSortedElemSet* workElements = & elemsNodes[0], copyElements[2];
2364   bool              makeWalls=true;
2365   if ( myIsPreviewMode )
2366   {
2367     SMDSAbs_ElementType select = SMDSAbs_All, avoid = SMDSAbs_Volume;
2368     TPreviewMesh * tmpMesh = getPreviewMesh();
2369     tmpMesh->Copy( elemsNodes[0], copyElements[0], select, avoid );
2370     tmpMesh->Copy( elemsNodes[1], copyElements[1], select, avoid );
2371     workElements = & copyElements[0];
2372     //makeWalls = false; -- faces are needed for preview
2373   }
2374
2375   TPythonDump aPythonDump; // it is here to prevent dump of getGroups()
2376
2377   gp_Ax1 Ax1 (gp_Pnt( theAxis.x,  theAxis.y,  theAxis.z ),
2378               gp_Vec( theAxis.vx, theAxis.vy, theAxis.vz ));
2379
2380   ::SMESH_MeshEditor::PGroupIDs groupIds =
2381       getEditor().RotationSweep (workElements, Ax1, theAngleInRadians,
2382                                  theNbOfSteps, theTolerance, theMakeGroups, makeWalls);
2383
2384   SMESH::ListOfGroups * aGroups = theMakeGroups ? getGroups( groupIds.get()) : 0;
2385
2386   declareMeshModified( /*isReComputeSafe=*/true ); // does not influence Compute()
2387
2388   if ( !myIsPreviewMode )
2389   {
2390     dumpGroupsList( aPythonDump, aGroups );
2391     aPythonDump << this<< ".RotationSweepObjects( "
2392                 << theNodes                  << ", "
2393                 << theEdges                  << ", "
2394                 << theFaces                  << ", "
2395                 << theAxis                   << ", "
2396                 << TVar( theAngleInRadians ) << ", "
2397                 << TVar( theNbOfSteps      ) << ", "
2398                 << TVar( theTolerance      ) << ", "
2399                 << theMakeGroups             << " )";
2400   }
2401
2402   return aGroups ? aGroups : new SMESH::ListOfGroups;
2403
2404   SMESH_CATCH( SMESH::throwCorbaException );
2405   return 0;
2406 }
2407
2408 namespace MeshEditor_I
2409 {
2410   /*!
2411    * \brief Structure used to pass extrusion parameters to ::SMESH_MeshEditor
2412    */
2413   struct ExtrusionParams : public ::SMESH_MeshEditor::ExtrusParam
2414   {
2415     bool myIsExtrusionByNormal;
2416
2417     static int makeFlags( CORBA::Boolean MakeGroups,
2418                           CORBA::Boolean ByAverageNormal = false,
2419                           CORBA::Boolean UseInputElemsOnly = false,
2420                           CORBA::Long    Flags = 0,
2421                           CORBA::Boolean MakeBoundary = true )
2422     {
2423       if ( MakeGroups       ) Flags |= ::SMESH_MeshEditor::EXTRUSION_FLAG_GROUPS;
2424       if ( ByAverageNormal  ) Flags |= ::SMESH_MeshEditor::EXTRUSION_FLAG_BY_AVG_NORMAL;
2425       if ( UseInputElemsOnly) Flags |= ::SMESH_MeshEditor::EXTRUSION_FLAG_USE_INPUT_ELEMS_ONLY;
2426       if ( MakeBoundary     ) Flags |= ::SMESH_MeshEditor::EXTRUSION_FLAG_BOUNDARY;
2427       return Flags;
2428     }
2429     // standard params
2430     ExtrusionParams(const SMESH::DirStruct &  theDir,
2431                     CORBA::Long               theNbOfSteps,
2432                     CORBA::Boolean            theMakeGroups):
2433       ::SMESH_MeshEditor::ExtrusParam ( gp_Vec( theDir.PS.x,
2434                                                 theDir.PS.y,
2435                                                 theDir.PS.z ),
2436                                         theNbOfSteps,
2437                                         makeFlags( theMakeGroups )),
2438       myIsExtrusionByNormal( false )
2439     {
2440     }
2441     // advanced params
2442     ExtrusionParams(const SMESH::DirStruct &  theDir,
2443                     CORBA::Long               theNbOfSteps,
2444                     CORBA::Boolean            theMakeGroups,
2445                     CORBA::Long               theExtrFlags,
2446                     CORBA::Double             theSewTolerance):
2447       ::SMESH_MeshEditor::ExtrusParam ( gp_Vec( theDir.PS.x,
2448                                                 theDir.PS.y,
2449                                                 theDir.PS.z ),
2450                                         theNbOfSteps,
2451                                         makeFlags( theMakeGroups, false, false,
2452                                                    theExtrFlags, false ),
2453                                         theSewTolerance ),
2454       myIsExtrusionByNormal( false )
2455     {
2456     }
2457     // params for extrusion by normal
2458     ExtrusionParams(CORBA::Double  theStepSize,
2459                     CORBA::Long    theNbOfSteps,
2460                     CORBA::Short   theDim,
2461                     CORBA::Boolean theUseInputElemsOnly,
2462                     CORBA::Boolean theByAverageNormal,
2463                     CORBA::Boolean theMakeGroups ):
2464       ::SMESH_MeshEditor::ExtrusParam ( theStepSize, 
2465                                         theNbOfSteps,
2466                                         makeFlags( theMakeGroups,
2467                                                    theByAverageNormal, theUseInputElemsOnly ),
2468                                         theDim),
2469       myIsExtrusionByNormal( true )
2470     {
2471     }
2472
2473     void SetNoGroups()
2474     {
2475       Flags() &= ~(::SMESH_MeshEditor::EXTRUSION_FLAG_GROUPS);
2476     }
2477   };
2478 }
2479
2480 //=======================================================================
2481 /*!
2482  * \brief Generate dim+1 elements by extrusion of elements along vector
2483  *  \param [in] edges - edges to extrude: a list including groups, sub-meshes or a mesh
2484  *  \param [in] faces - faces to extrude: a list including groups, sub-meshes or a mesh
2485  *  \param [in] nodes - nodes to extrude: a list including groups, sub-meshes or a mesh
2486  *  \param [in] stepVector - vector giving direction and distance of an extrusion step
2487  *  \param [in] nbOfSteps - number of elements to generate from one element
2488  *  \param [in] toMakeGroups - if true, new elements will be included into new groups
2489  *              corresponding to groups the input elements included in.
2490  *  \return ListOfGroups - new groups craeted if \a toMakeGroups is true
2491  */
2492 //=======================================================================
2493
2494 SMESH::ListOfGroups*
2495 SMESH_MeshEditor_i::ExtrusionSweepObjects(const SMESH::ListOfIDSources & theNodes,
2496                                           const SMESH::ListOfIDSources & theEdges,
2497                                           const SMESH::ListOfIDSources & theFaces,
2498                                           const SMESH::DirStruct &       theStepVector,
2499                                           CORBA::Long                    theNbOfSteps,
2500                                           CORBA::Boolean                 theToMakeGroups)
2501   throw (SALOME::SALOME_Exception)
2502 {
2503   SMESH_TRY;
2504   initData();
2505
2506   ExtrusionParams params( theStepVector, theNbOfSteps, theToMakeGroups );
2507
2508   TIDSortedElemSet elemsNodes[2];
2509   for ( int i = 0, nb = theNodes.length(); i < nb; ++i ) {
2510     SMDS_ElemIteratorPtr nIt = myMesh_i->GetElements( theNodes[i], SMESH::NODE );
2511     while ( nIt->more() ) elemsNodes[1].insert( nIt->next() );
2512   }
2513   for ( int i = 0, nb = theEdges.length(); i < nb; ++i )
2514     idSourceToSet( theEdges[i], getMeshDS(), elemsNodes[0], SMDSAbs_Edge );
2515   for ( int i = 0, nb = theFaces.length(); i < nb; ++i )
2516     idSourceToSet( theFaces[i], getMeshDS(), elemsNodes[0], SMDSAbs_Face );
2517
2518   TIDSortedElemSet* workElements = & elemsNodes[0], copyElements[2];
2519   if ( myIsPreviewMode )
2520   {
2521     SMDSAbs_ElementType previewType = SMDSAbs_All; //SMDSAbs_Face;
2522     // if ( (*elemsNodes.begin())->GetType() == SMDSAbs_Node )
2523     //   previewType = SMDSAbs_Edge;
2524
2525     SMDSAbs_ElementType select = SMDSAbs_All, avoid = SMDSAbs_Volume;
2526     TPreviewMesh * tmpMesh = getPreviewMesh();
2527     tmpMesh->Copy( elemsNodes[0], copyElements[0], select, avoid );
2528     tmpMesh->Copy( elemsNodes[1], copyElements[1], select, avoid );
2529     workElements = & copyElements[0];
2530
2531     params.SetNoGroups();
2532   }
2533   TPythonDump aPythonDump; // it is here to prevent dump of getGroups()
2534
2535   ::SMESH_MeshEditor::TTElemOfElemListMap aHistory;
2536   ::SMESH_MeshEditor::PGroupIDs groupIds =
2537       getEditor().ExtrusionSweep( workElements, params, aHistory );
2538
2539   SMESH::ListOfGroups * aGroups = theToMakeGroups ? getGroups( groupIds.get()) : 0;
2540
2541   declareMeshModified( /*isReComputeSafe=*/true ); // does not influence Compute()
2542
2543   if ( !myIsPreviewMode )
2544   {
2545     dumpGroupsList( aPythonDump, aGroups );
2546     aPythonDump << this<< ".ExtrusionSweepObjects( "
2547                 << theNodes             << ", "
2548                 << theEdges             << ", "
2549                 << theFaces             << ", "
2550                 << theStepVector        << ", "
2551                 << TVar( theNbOfSteps ) << ", "
2552                 << theToMakeGroups      << " )";
2553   }
2554
2555   return aGroups ? aGroups : new SMESH::ListOfGroups;
2556
2557   SMESH_CATCH( SMESH::throwCorbaException );
2558   return 0;
2559 }
2560
2561 //=======================================================================
2562 //function : ExtrusionByNormal
2563 //purpose  :
2564 //=======================================================================
2565
2566 SMESH::ListOfGroups*
2567 SMESH_MeshEditor_i::ExtrusionByNormal(const SMESH::ListOfIDSources& objects,
2568                                       CORBA::Double                 stepSize,
2569                                       CORBA::Long                   nbOfSteps,
2570                                       CORBA::Boolean                byAverageNormal,
2571                                       CORBA::Boolean                useInputElemsOnly,
2572                                       CORBA::Boolean                makeGroups,
2573                                       CORBA::Short                  dim)
2574   throw (SALOME::SALOME_Exception)
2575 {
2576   SMESH_TRY;
2577   initData();
2578
2579   TPythonDump aPythonDump; // it is here to prevent dump of GetGroups()
2580
2581   ExtrusionParams params( stepSize, nbOfSteps, dim,
2582                           byAverageNormal, useInputElemsOnly, makeGroups );
2583
2584   SMDSAbs_ElementType elemType = ( dim == 1 ? SMDSAbs_Edge : SMDSAbs_Face );
2585   if ( objects.length() > 0 && !SMESH::DownCast<SMESH_Mesh_i*>( objects[0] ))
2586   {
2587     SMESH::array_of_ElementType_var elemTypes = objects[0]->GetTypes();
2588     if (( elemTypes->length() == 1 ) &&
2589         ( elemTypes[0] == SMESH::EDGE || elemTypes[0] == SMESH::FACE ))
2590       elemType = ( SMDSAbs_ElementType ) elemTypes[0];
2591   }
2592
2593   TIDSortedElemSet elemsNodes[2];
2594   for ( int i = 0, nb = objects.length(); i < nb; ++i )
2595     idSourceToSet( objects[i], getMeshDS(), elemsNodes[0], elemType );
2596
2597   TIDSortedElemSet* workElements = & elemsNodes[0], copyElements[2];
2598   if ( myIsPreviewMode )
2599   {
2600     SMDSAbs_ElementType previewType = SMDSAbs_Face;
2601     SMDSAbs_ElementType select = SMDSAbs_All, avoid = SMDSAbs_Volume;
2602     TPreviewMesh * tmpMesh = getPreviewMesh( previewType );
2603     tmpMesh->Copy( elemsNodes[0], copyElements[0], select, avoid );
2604     workElements = & copyElements[0];
2605
2606     params.SetNoGroups();
2607   }
2608
2609   ::SMESH_MeshEditor::TTElemOfElemListMap aHistory;
2610   ::SMESH_MeshEditor::PGroupIDs groupIds =
2611       getEditor().ExtrusionSweep( workElements, params, aHistory );
2612
2613   SMESH::ListOfGroups * aGroups = makeGroups ? getGroups( groupIds.get()) : 0;
2614
2615   if (!myIsPreviewMode) {
2616     dumpGroupsList(aPythonDump, aGroups);
2617     aPythonDump << this << ".ExtrusionByNormal( " << objects
2618                 << ", " << TVar( stepSize )
2619                 << ", " << TVar( nbOfSteps )
2620                 << ", " << byAverageNormal
2621                 << ", " << useInputElemsOnly
2622                 << ", " << makeGroups
2623                 << ", " << dim
2624                 << " )";
2625   }
2626
2627   declareMeshModified( /*isReComputeSafe=*/true ); // does not influence Compute()
2628
2629   return aGroups ? aGroups : new SMESH::ListOfGroups;
2630
2631   SMESH_CATCH( SMESH::throwCorbaException );
2632   return 0;
2633 }
2634
2635 //=======================================================================
2636 //function : AdvancedExtrusion
2637 //purpose  :
2638 //=======================================================================
2639
2640 SMESH::ListOfGroups*
2641 SMESH_MeshEditor_i::AdvancedExtrusion(const SMESH::long_array & theIDsOfElements,
2642                                       const SMESH::DirStruct &  theStepVector,
2643                                       CORBA::Long               theNbOfSteps,
2644                                       CORBA::Long               theExtrFlags,
2645                                       CORBA::Double             theSewTolerance,
2646                                       CORBA::Boolean            theMakeGroups)
2647   throw (SALOME::SALOME_Exception)
2648 {
2649   SMESH_TRY;
2650   initData();
2651
2652   TPythonDump aPythonDump; // it is here to prevent dump of getGroups()
2653
2654   ExtrusionParams params( theStepVector, theNbOfSteps, theMakeGroups,
2655                           theExtrFlags, theSewTolerance );
2656
2657   TIDSortedElemSet elemsNodes[2];
2658   arrayToSet( theIDsOfElements, getMeshDS(), elemsNodes[0] );
2659
2660   ::SMESH_MeshEditor::TTElemOfElemListMap aHistory;
2661   ::SMESH_MeshEditor::PGroupIDs groupIds =
2662       getEditor().ExtrusionSweep( elemsNodes, params, aHistory );
2663
2664   SMESH::ListOfGroups * aGroups = theMakeGroups ? getGroups( groupIds.get()) : 0;
2665
2666   declareMeshModified( /*isReComputeSafe=*/true ); // does not influence Compute()
2667
2668   if ( !myIsPreviewMode ) {
2669     dumpGroupsList(aPythonDump, aGroups);
2670     aPythonDump << this << ".AdvancedExtrusion( "
2671                 << theIDsOfElements << ", "
2672                 << theStepVector << ", "
2673                 << theNbOfSteps << ", "
2674                 << theExtrFlags << ", "
2675                 << theSewTolerance << ", "
2676                 << theMakeGroups << " )";
2677   }
2678
2679   return aGroups ? aGroups : new SMESH::ListOfGroups;
2680
2681   SMESH_CATCH( SMESH::throwCorbaException );
2682   return 0;
2683 }
2684
2685 //================================================================================
2686 /*!
2687  * \brief Convert extrusion error to IDL enum
2688  */
2689 //================================================================================
2690
2691 namespace
2692 {
2693 #define RETCASE(enm) case ::SMESH_MeshEditor::enm: return SMESH::SMESH_MeshEditor::enm;
2694
2695   SMESH::SMESH_MeshEditor::Extrusion_Error convExtrError( ::SMESH_MeshEditor::Extrusion_Error e )
2696   {
2697     switch ( e ) {
2698       RETCASE( EXTR_OK );
2699       RETCASE( EXTR_NO_ELEMENTS );
2700       RETCASE( EXTR_PATH_NOT_EDGE );
2701       RETCASE( EXTR_BAD_PATH_SHAPE );
2702       RETCASE( EXTR_BAD_STARTING_NODE );
2703       RETCASE( EXTR_BAD_ANGLES_NUMBER );
2704       RETCASE( EXTR_CANT_GET_TANGENT );
2705     }
2706     return SMESH::SMESH_MeshEditor::EXTR_OK;
2707   }
2708 }
2709
2710 //=======================================================================
2711 //function : extrusionAlongPath
2712 //purpose  :
2713 //=======================================================================
2714 SMESH::ListOfGroups*
2715 SMESH_MeshEditor_i::ExtrusionAlongPathObjects(const SMESH::ListOfIDSources & theNodes,
2716                                               const SMESH::ListOfIDSources & theEdges,
2717                                               const SMESH::ListOfIDSources & theFaces,
2718                                               SMESH::SMESH_IDSource_ptr      thePathMesh,
2719                                               GEOM::GEOM_Object_ptr          thePathShape,
2720                                               CORBA::Long                    theNodeStart,
2721                                               CORBA::Boolean                 theHasAngles,
2722                                               const SMESH::double_array &    theAngles,
2723                                               CORBA::Boolean                 theLinearVariation,
2724                                               CORBA::Boolean                 theHasRefPoint,
2725                                               const SMESH::PointStruct &     theRefPoint,
2726                                               bool                           theMakeGroups,
2727                                               SMESH::SMESH_MeshEditor::Extrusion_Error& theError)
2728   throw (SALOME::SALOME_Exception)
2729 {
2730   SMESH_TRY;
2731   initData();
2732
2733   SMESH::ListOfGroups_var aGroups = new SMESH::ListOfGroups;
2734
2735   theError = SMESH::SMESH_MeshEditor::EXTR_BAD_PATH_SHAPE;
2736   if ( thePathMesh->_is_nil() )
2737     return aGroups._retn();
2738
2739   // get a sub-mesh
2740   SMESH_subMesh* aSubMesh = 0;
2741   SMESH_Mesh_i* aMeshImp = SMESH::DownCast<SMESH_Mesh_i*>( thePathMesh );
2742   if ( thePathShape->_is_nil() )
2743   {
2744     // thePathMesh should be either a sub-mesh or a mesh with 1D elements only
2745     if ( SMESH_subMesh_i* sm = SMESH::DownCast<SMESH_subMesh_i*>( thePathMesh ))
2746     {
2747       SMESH::SMESH_Mesh_var mesh = thePathMesh->GetMesh();
2748       aMeshImp = SMESH::DownCast<SMESH_Mesh_i*>( mesh );
2749       if ( !aMeshImp ) return aGroups._retn();
2750       aSubMesh = aMeshImp->GetImpl().GetSubMeshContaining( sm->GetId() );
2751       if ( !aSubMesh ) return aGroups._retn();
2752     }
2753     else if ( !aMeshImp ||
2754               aMeshImp->NbEdges() != aMeshImp->NbElements() )
2755     {
2756       return aGroups._retn();
2757     }
2758   }
2759   else
2760   {
2761     if ( !aMeshImp ) return aGroups._retn();
2762     TopoDS_Shape aShape = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape( thePathShape );
2763     aSubMesh = aMeshImp->GetImpl().GetSubMesh( aShape );
2764     if ( !aSubMesh || !aSubMesh->GetSubMeshDS() )
2765       return aGroups._retn();
2766   }
2767
2768   SMDS_MeshNode* nodeStart =
2769     (SMDS_MeshNode*)aMeshImp->GetImpl().GetMeshDS()->FindNode(theNodeStart);
2770   if ( !nodeStart ) {
2771     theError = SMESH::SMESH_MeshEditor::EXTR_BAD_STARTING_NODE;
2772     return aGroups._retn();
2773   }
2774
2775   TIDSortedElemSet elemsNodes[2];
2776   for ( int i = 0, nb = theNodes.length(); i < nb; ++i ) {
2777     SMDS_ElemIteratorPtr nIt = myMesh_i->GetElements( theNodes[i], SMESH::NODE );
2778     while ( nIt->more() ) elemsNodes[1].insert( nIt->next() );
2779   }
2780   for ( int i = 0, nb = theEdges.length(); i < nb; ++i )
2781     idSourceToSet( theEdges[i], getMeshDS(), elemsNodes[0], SMDSAbs_Edge );
2782   for ( int i = 0, nb = theFaces.length(); i < nb; ++i )
2783     idSourceToSet( theFaces[i], getMeshDS(), elemsNodes[0], SMDSAbs_Face );
2784
2785   list<double> angles;
2786   for (int i = 0; i < theAngles.length(); i++) {
2787     angles.push_back( theAngles[i] );
2788   }
2789
2790   gp_Pnt refPnt( theRefPoint.x, theRefPoint.y, theRefPoint.z );
2791
2792   int nbOldGroups = myMesh->NbGroup();
2793
2794   TIDSortedElemSet* workElements = & elemsNodes[0], copyElements[2];
2795   if ( myIsPreviewMode )
2796   {
2797     SMDSAbs_ElementType select = SMDSAbs_All, avoid = SMDSAbs_Volume;
2798     TPreviewMesh * tmpMesh = getPreviewMesh();
2799     tmpMesh->Copy( elemsNodes[0], copyElements[0], select, avoid );
2800     tmpMesh->Copy( elemsNodes[1], copyElements[1], select, avoid );
2801     workElements = & copyElements[0];
2802     theMakeGroups = false;
2803   }
2804
2805   ::SMESH_MeshEditor::Extrusion_Error error;
2806   if ( !aSubMesh )
2807     error = getEditor().ExtrusionAlongTrack( workElements, &(aMeshImp->GetImpl()), nodeStart,
2808                                              theHasAngles, angles, theLinearVariation,
2809                                              theHasRefPoint, refPnt, theMakeGroups );
2810   else
2811     error = getEditor().ExtrusionAlongTrack( workElements, aSubMesh, nodeStart,
2812                                              theHasAngles, angles, theLinearVariation,
2813                                              theHasRefPoint, refPnt, theMakeGroups );
2814
2815   declareMeshModified( /*isReComputeSafe=*/true );
2816   theError = convExtrError( error );
2817
2818   TPythonDump aPythonDump; // it is here to prevent dump of getGroups()
2819   if ( theMakeGroups ) {
2820     list<int> groupIDs = myMesh->GetGroupIds();
2821     list<int>::iterator newBegin = groupIDs.begin();
2822     std::advance( newBegin, nbOldGroups ); // skip old groups
2823     groupIDs.erase( groupIDs.begin(), newBegin );
2824     aGroups = getGroups( & groupIDs );
2825     if ( ! &aGroups.in() ) aGroups = new SMESH::ListOfGroups;
2826   }
2827
2828   if ( !myIsPreviewMode ) {
2829     aPythonDump << "(" << aGroups << ", error) = "
2830                 << this << ".ExtrusionAlongPathObjects( "
2831                 << theNodes            << ", "
2832                 << theEdges            << ", "
2833                 << theFaces            << ", "
2834                 << thePathMesh         << ", "
2835                 << thePathShape        << ", "
2836                 << theNodeStart        << ", "
2837                 << theHasAngles        << ", "
2838                 << theAngles           << ", "
2839                 << theLinearVariation  << ", "
2840                 << theHasRefPoint      << ", "
2841                 << "SMESH.PointStruct( "
2842                 << ( theHasRefPoint ? theRefPoint.x : 0 ) << ", "
2843                 << ( theHasRefPoint ? theRefPoint.y : 0 ) << ", "
2844                 << ( theHasRefPoint ? theRefPoint.z : 0 ) << " ), "
2845                 << theMakeGroups       << " )";
2846   }
2847
2848   return aGroups._retn();
2849
2850   SMESH_CATCH( SMESH::throwCorbaException );
2851   return 0;
2852 }
2853
2854 //================================================================================
2855 /*!
2856  * \brief Compute rotation angles for ExtrusionAlongPath as linear variation
2857  * of given angles along path steps
2858  * \param PathMesh mesh containing a 1D sub-mesh on the edge, along
2859  *                which proceeds the extrusion
2860  * \param PathShape is shape(edge); as the mesh can be complex, the edge
2861  *                 is used to define the sub-mesh for the path
2862  */
2863 //================================================================================
2864
2865 SMESH::double_array*
2866 SMESH_MeshEditor_i::LinearAnglesVariation(SMESH::SMESH_Mesh_ptr       thePathMesh,
2867                                           GEOM::GEOM_Object_ptr       thePathShape,
2868                                           const SMESH::double_array & theAngles)
2869 {
2870   SMESH::double_array_var aResult = new SMESH::double_array();
2871   int nbAngles = theAngles.length();
2872   if ( nbAngles > 0 && !thePathMesh->_is_nil() && !thePathShape->_is_nil() )
2873   {
2874     SMESH_Mesh_i* aMeshImp = SMESH::DownCast<SMESH_Mesh_i*>( thePathMesh );
2875     TopoDS_Shape aShape = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape( thePathShape );
2876     SMESH_subMesh* aSubMesh = aMeshImp->GetImpl().GetSubMesh( aShape );
2877     if ( !aSubMesh || !aSubMesh->GetSubMeshDS())
2878       return aResult._retn();
2879     int nbSteps = aSubMesh->GetSubMeshDS()->NbElements();
2880     if ( nbSteps == nbAngles )
2881     {
2882       aResult.inout() = theAngles;
2883     }
2884     else
2885     {
2886       aResult->length( nbSteps );
2887       double rAn2St = double( nbAngles ) / double( nbSteps );
2888       double angPrev = 0, angle;
2889       for ( int iSt = 0; iSt < nbSteps; ++iSt )
2890       {
2891         double angCur = rAn2St * ( iSt+1 );
2892         double angCurFloor  = floor( angCur );
2893         double angPrevFloor = floor( angPrev );
2894         if ( angPrevFloor == angCurFloor )
2895           angle = rAn2St * theAngles[ int( angCurFloor ) ];
2896         else
2897         {
2898           int iP = int( angPrevFloor );
2899           double angPrevCeil = ceil(angPrev);
2900           angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
2901
2902           int iC = int( angCurFloor );
2903           if ( iC < nbAngles )
2904             angle += ( angCur - angCurFloor ) * theAngles[ iC ];
2905
2906           iP = int( angPrevCeil );
2907           while ( iC-- > iP )
2908             angle += theAngles[ iC ];
2909         }
2910         aResult[ iSt ] = angle;
2911         angPrev = angCur;
2912       }
2913     }
2914   }
2915   // Update Python script
2916   TPythonDump() << "rotAngles = " << theAngles;
2917   TPythonDump() << "rotAngles = " << this << ".LinearAnglesVariation( "
2918                 << thePathMesh  << ", "
2919                 << thePathShape << ", "
2920                 << "rotAngles )";
2921
2922   return aResult._retn();
2923 }
2924
2925 //=======================================================================
2926 //function : mirror
2927 //purpose  :
2928 //=======================================================================
2929
2930 SMESH::ListOfGroups*
2931 SMESH_MeshEditor_i::mirror(TIDSortedElemSet &                  theElements,
2932                            const SMESH::AxisStruct &           theAxis,
2933                            SMESH::SMESH_MeshEditor::MirrorType theMirrorType,
2934                            CORBA::Boolean                      theCopy,
2935                            bool                                theMakeGroups,
2936                            ::SMESH_Mesh*                       theTargetMesh)
2937   throw (SALOME::SALOME_Exception)
2938 {
2939   SMESH_TRY;
2940   initData();
2941
2942   gp_Pnt P ( theAxis.x, theAxis.y, theAxis.z );
2943   gp_Vec V ( theAxis.vx, theAxis.vy, theAxis.vz );
2944
2945   if ( theTargetMesh )
2946     theCopy = false;
2947
2948   gp_Trsf aTrsf;
2949   switch ( theMirrorType ) {
2950   case  SMESH::SMESH_MeshEditor::POINT:
2951     aTrsf.SetMirror( P );
2952     break;
2953   case  SMESH::SMESH_MeshEditor::AXIS:
2954     aTrsf.SetMirror( gp_Ax1( P, V ));
2955     break;
2956   default:
2957     aTrsf.SetMirror( gp_Ax2( P, V ));
2958   }
2959
2960   TIDSortedElemSet  copyElements;
2961   TIDSortedElemSet* workElements = & theElements;
2962
2963   if ( myIsPreviewMode )
2964   {
2965     TPreviewMesh * tmpMesh = getPreviewMesh();
2966     tmpMesh->Copy( theElements, copyElements);
2967     if ( !theCopy && !theTargetMesh )
2968     {
2969       TIDSortedElemSet elemsAround, elemsAroundCopy;
2970       getElementsAround( theElements, getMeshDS(), elemsAround );
2971       tmpMesh->Copy( elemsAround, elemsAroundCopy);
2972     }
2973     workElements = & copyElements;
2974     theMakeGroups = false;
2975   }
2976
2977   ::SMESH_MeshEditor::PGroupIDs groupIds =
2978       getEditor().Transform (*workElements, aTrsf, theCopy, theMakeGroups, theTargetMesh);
2979
2980   if ( theCopy && !myIsPreviewMode)
2981   {
2982     if ( theTargetMesh )
2983     {
2984       theTargetMesh->GetMeshDS()->Modified();
2985     }
2986     else
2987     {
2988       declareMeshModified( /*isReComputeSafe=*/false );
2989     }
2990   }
2991   return theMakeGroups ? getGroups(groupIds.get()) : 0;
2992
2993   SMESH_CATCH( SMESH::throwCorbaException );
2994   return 0;
2995 }
2996
2997 //=======================================================================
2998 //function : Mirror
2999 //purpose  :
3000 //=======================================================================
3001
3002 void SMESH_MeshEditor_i::Mirror(const SMESH::long_array &           theIDsOfElements,
3003                                 const SMESH::AxisStruct &           theAxis,
3004                                 SMESH::SMESH_MeshEditor::MirrorType theMirrorType,
3005                                 CORBA::Boolean                      theCopy)
3006   throw (SALOME::SALOME_Exception)
3007 {
3008   if ( !myIsPreviewMode ) {
3009     TPythonDump() << this << ".Mirror( "
3010                   << theIDsOfElements              << ", "
3011                   << theAxis                       << ", "
3012                   << mirrorTypeName(theMirrorType) << ", "
3013                   << theCopy                       << " )";
3014   }
3015   if ( theIDsOfElements.length() > 0 )
3016   {
3017     TIDSortedElemSet elements;
3018     arrayToSet(theIDsOfElements, getMeshDS(), elements);
3019     mirror(elements, theAxis, theMirrorType, theCopy, false);
3020   }
3021 }
3022
3023
3024 //=======================================================================
3025 //function : MirrorObject
3026 //purpose  :
3027 //=======================================================================
3028
3029 void SMESH_MeshEditor_i::MirrorObject(SMESH::SMESH_IDSource_ptr           theObject,
3030                                       const SMESH::AxisStruct &           theAxis,
3031                                       SMESH::SMESH_MeshEditor::MirrorType theMirrorType,
3032                                       CORBA::Boolean                      theCopy)
3033   throw (SALOME::SALOME_Exception)
3034 {
3035   if ( !myIsPreviewMode ) {
3036     TPythonDump() << this << ".MirrorObject( "
3037                   << theObject                     << ", "
3038                   << theAxis                       << ", "
3039                   << mirrorTypeName(theMirrorType) << ", "
3040                   << theCopy                       << " )";
3041   }
3042   TIDSortedElemSet elements;
3043
3044   bool emptyIfIsMesh = myIsPreviewMode ? false : true;
3045
3046   if (idSourceToSet(theObject, getMeshDS(), elements, SMDSAbs_All, emptyIfIsMesh))
3047     mirror(elements, theAxis, theMirrorType, theCopy, false);
3048 }
3049
3050 //=======================================================================
3051 //function : MirrorMakeGroups
3052 //purpose  :
3053 //=======================================================================
3054
3055 SMESH::ListOfGroups*
3056 SMESH_MeshEditor_i::MirrorMakeGroups(const SMESH::long_array&            theIDsOfElements,
3057                                      const SMESH::AxisStruct&            theMirror,
3058                                      SMESH::SMESH_MeshEditor::MirrorType theMirrorType)
3059   throw (SALOME::SALOME_Exception)
3060 {
3061   TPythonDump aPythonDump; // it is here to prevent dump of GetGroups()
3062
3063   SMESH::ListOfGroups * aGroups = 0;
3064   if ( theIDsOfElements.length() > 0 )
3065   {
3066     TIDSortedElemSet elements;
3067     arrayToSet(theIDsOfElements, getMeshDS(), elements);
3068     aGroups = mirror(elements, theMirror, theMirrorType, true, true);
3069   }
3070   if (!myIsPreviewMode) {
3071     dumpGroupsList(aPythonDump, aGroups);
3072     aPythonDump << this << ".MirrorMakeGroups( "
3073                 << theIDsOfElements              << ", "
3074                 << theMirror                     << ", "
3075                 << mirrorTypeName(theMirrorType) << " )";
3076   }
3077   return aGroups;
3078 }
3079
3080 //=======================================================================
3081 //function : MirrorObjectMakeGroups
3082 //purpose  :
3083 //=======================================================================
3084
3085 SMESH::ListOfGroups*
3086 SMESH_MeshEditor_i::MirrorObjectMakeGroups(SMESH::SMESH_IDSource_ptr           theObject,
3087                                            const SMESH::AxisStruct&            theMirror,
3088                                            SMESH::SMESH_MeshEditor::MirrorType theMirrorType)
3089   throw (SALOME::SALOME_Exception)
3090 {
3091   TPythonDump aPythonDump; // it is here to prevent dump of GetGroups()
3092
3093   SMESH::ListOfGroups * aGroups = 0;
3094   TIDSortedElemSet elements;
3095   if ( idSourceToSet(theObject, getMeshDS(), elements, SMDSAbs_All, /*emptyIfIsMesh=*/1))
3096     aGroups = mirror(elements, theMirror, theMirrorType, true, true);
3097
3098   if (!myIsPreviewMode)
3099   {
3100     dumpGroupsList(aPythonDump,aGroups);
3101     aPythonDump << this << ".MirrorObjectMakeGroups( "
3102                 << theObject                     << ", "
3103                 << theMirror                     << ", "
3104                 << mirrorTypeName(theMirrorType) << " )";
3105   }
3106   return aGroups;
3107 }
3108
3109 //=======================================================================
3110 //function : MirrorMakeMesh
3111 //purpose  :
3112 //=======================================================================
3113
3114 SMESH::SMESH_Mesh_ptr
3115 SMESH_MeshEditor_i::MirrorMakeMesh(const SMESH::long_array&            theIDsOfElements,
3116                                    const SMESH::AxisStruct&            theMirror,
3117                                    SMESH::SMESH_MeshEditor::MirrorType theMirrorType,
3118                                    CORBA::Boolean                      theCopyGroups,
3119                                    const char*                         theMeshName)
3120   throw (SALOME::SALOME_Exception)
3121 {
3122   SMESH_Mesh_i* mesh_i;
3123   SMESH::SMESH_Mesh_var mesh;
3124   { // open new scope to dump "MakeMesh" command
3125     // and then "GetGroups" using SMESH_Mesh::GetGroups()
3126
3127     TPythonDump pydump; // to prevent dump at mesh creation
3128
3129     mesh = makeMesh( theMeshName );
3130     mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh );
3131     if (mesh_i && theIDsOfElements.length() > 0 )
3132     {
3133       TIDSortedElemSet elements;
3134       arrayToSet(theIDsOfElements, getMeshDS(), elements);
3135       mirror(elements, theMirror, theMirrorType,
3136              false, theCopyGroups, & mesh_i->GetImpl());
3137       mesh_i->CreateGroupServants();
3138     }
3139
3140     if (!myIsPreviewMode) {
3141       pydump << mesh << " = " << this << ".MirrorMakeMesh( "
3142              << theIDsOfElements              << ", "
3143              << theMirror                     << ", "
3144              << mirrorTypeName(theMirrorType) << ", "
3145              << theCopyGroups                 << ", '"
3146              << theMeshName                   << "' )";
3147     }
3148   }
3149
3150   //dump "GetGroups"
3151   if (!myIsPreviewMode && mesh_i)
3152     mesh_i->GetGroups();
3153
3154   return mesh._retn();
3155 }
3156
3157 //=======================================================================
3158 //function : MirrorObjectMakeMesh
3159 //purpose  :
3160 //=======================================================================
3161
3162 SMESH::SMESH_Mesh_ptr
3163 SMESH_MeshEditor_i::MirrorObjectMakeMesh(SMESH::SMESH_IDSource_ptr           theObject,
3164                                          const SMESH::AxisStruct&            theMirror,
3165                                          SMESH::SMESH_MeshEditor::MirrorType theMirrorType,
3166                                          CORBA::Boolean                      theCopyGroups,
3167                                          const char*                         theMeshName)
3168   throw (SALOME::SALOME_Exception)
3169 {
3170   SMESH_Mesh_i* mesh_i;
3171   SMESH::SMESH_Mesh_var mesh;
3172   { // open new scope to dump "MakeMesh" command
3173     // and then "GetGroups" using SMESH_Mesh::GetGroups()
3174
3175     TPythonDump pydump; // to prevent dump at mesh creation
3176
3177     mesh = makeMesh( theMeshName );
3178     mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh );
3179     TIDSortedElemSet elements;
3180     if ( mesh_i &&
3181          idSourceToSet(theObject, getMeshDS(), elements, SMDSAbs_All, /*emptyIfIsMesh=*/1))
3182     {
3183       mirror(elements, theMirror, theMirrorType,
3184              false, theCopyGroups, & mesh_i->GetImpl());
3185       mesh_i->CreateGroupServants();
3186     }
3187     if (!myIsPreviewMode) {
3188       pydump << mesh << " = " << this << ".MirrorObjectMakeMesh( "
3189              << theObject                     << ", "
3190              << theMirror                     << ", "
3191              << mirrorTypeName(theMirrorType) << ", "
3192              << theCopyGroups                 << ", '"
3193              << theMeshName                   << "' )";
3194     }
3195   }
3196
3197   //dump "GetGroups"
3198   if (!myIsPreviewMode && mesh_i)
3199     mesh_i->GetGroups();
3200
3201   return mesh._retn();
3202 }
3203
3204 //=======================================================================
3205 //function : translate
3206 //purpose  :
3207 //=======================================================================
3208
3209 SMESH::ListOfGroups*
3210 SMESH_MeshEditor_i::translate(TIDSortedElemSet        & theElements,
3211                               const SMESH::DirStruct &  theVector,
3212                               CORBA::Boolean            theCopy,
3213                               bool                      theMakeGroups,
3214                               ::SMESH_Mesh*             theTargetMesh)
3215   throw (SALOME::SALOME_Exception)
3216 {
3217   SMESH_TRY;
3218   initData();
3219
3220   if ( theTargetMesh )
3221     theCopy = false;
3222
3223   gp_Trsf aTrsf;
3224   const SMESH::PointStruct * P = &theVector.PS;
3225   aTrsf.SetTranslation( gp_Vec( P->x, P->y, P->z ));
3226
3227   TIDSortedElemSet  copyElements;
3228   TIDSortedElemSet* workElements = &theElements;
3229
3230   if ( myIsPreviewMode )
3231   {
3232     TPreviewMesh * tmpMesh = getPreviewMesh();
3233     tmpMesh->Copy( theElements, copyElements);
3234     if ( !theCopy && !theTargetMesh )
3235     {
3236       TIDSortedElemSet elemsAround, elemsAroundCopy;
3237       getElementsAround( theElements, getMeshDS(), elemsAround );
3238       tmpMesh->Copy( elemsAround, elemsAroundCopy);
3239     }
3240     workElements = & copyElements;
3241     theMakeGroups = false;
3242   }
3243
3244   ::SMESH_MeshEditor::PGroupIDs groupIds =
3245       getEditor().Transform (*workElements, aTrsf, theCopy, theMakeGroups, theTargetMesh);
3246
3247   if ( theCopy && !myIsPreviewMode )
3248   {
3249     if ( theTargetMesh )
3250     {
3251       theTargetMesh->GetMeshDS()->Modified();
3252     }
3253     else
3254     {
3255       declareMeshModified( /*isReComputeSafe=*/false );
3256     }
3257   }
3258
3259   return theMakeGroups ? getGroups(groupIds.get()) : 0;
3260
3261   SMESH_CATCH( SMESH::throwCorbaException );
3262   return 0;
3263 }
3264
3265 //=======================================================================
3266 //function : Translate
3267 //purpose  :
3268 //=======================================================================
3269
3270 void SMESH_MeshEditor_i::Translate(const SMESH::long_array & theIDsOfElements,
3271                                    const SMESH::DirStruct &  theVector,
3272                                    CORBA::Boolean            theCopy)
3273   throw (SALOME::SALOME_Exception)
3274 {
3275   if (!myIsPreviewMode) {
3276     TPythonDump() << this << ".Translate( "
3277                   << theIDsOfElements << ", "
3278                   << theVector        << ", "
3279                   << theCopy          << " )";
3280   }
3281   if (theIDsOfElements.length()) {
3282     TIDSortedElemSet elements;
3283     arrayToSet(theIDsOfElements, getMeshDS(), elements);
3284     translate(elements, theVector, theCopy, false);
3285   }
3286 }
3287
3288 //=======================================================================
3289 //function : TranslateObject
3290 //purpose  :
3291 //=======================================================================
3292
3293 void SMESH_MeshEditor_i::TranslateObject(SMESH::SMESH_IDSource_ptr theObject,
3294                                          const SMESH::DirStruct &  theVector,
3295                                          CORBA::Boolean            theCopy)
3296   throw (SALOME::SALOME_Exception)
3297 {
3298   if (!myIsPreviewMode) {
3299     TPythonDump() << this << ".TranslateObject( "
3300                   << theObject << ", "
3301                   << theVector << ", "
3302                   << theCopy   << " )";
3303   }
3304   TIDSortedElemSet elements;
3305
3306   bool emptyIfIsMesh = myIsPreviewMode ? false : true;
3307
3308   if (idSourceToSet(theObject, getMeshDS(), elements, SMDSAbs_All, emptyIfIsMesh))
3309     translate(elements, theVector, theCopy, false);
3310 }
3311
3312 //=======================================================================
3313 //function : TranslateMakeGroups
3314 //purpose  :
3315 //=======================================================================
3316
3317 SMESH::ListOfGroups*
3318 SMESH_MeshEditor_i::TranslateMakeGroups(const SMESH::long_array& theIDsOfElements,
3319                                         const SMESH::DirStruct&  theVector)
3320   throw (SALOME::SALOME_Exception)
3321 {
3322   TPythonDump aPythonDump; // it is here to prevent dump of GetGroups()
3323
3324   SMESH::ListOfGroups * aGroups = 0;
3325   if (theIDsOfElements.length()) {
3326     TIDSortedElemSet elements;
3327     arrayToSet(theIDsOfElements, getMeshDS(), elements);
3328     aGroups = translate(elements,theVector,true,true);
3329   }
3330   if (!myIsPreviewMode) {
3331     dumpGroupsList(aPythonDump, aGroups);
3332     aPythonDump << this << ".TranslateMakeGroups( "
3333                 << theIDsOfElements << ", "
3334                 << theVector        << " )";
3335   }
3336   return aGroups;
3337 }
3338
3339 //=======================================================================
3340 //function : TranslateObjectMakeGroups
3341 //purpose  :
3342 //=======================================================================
3343
3344 SMESH::ListOfGroups*
3345 SMESH_MeshEditor_i::TranslateObjectMakeGroups(SMESH::SMESH_IDSource_ptr theObject,
3346                                               const SMESH::DirStruct&   theVector)
3347   throw (SALOME::SALOME_Exception)
3348 {
3349   TPythonDump aPythonDump; // it is here to prevent dump of GetGroups()
3350
3351   SMESH::ListOfGroups * aGroups = 0;
3352   TIDSortedElemSet elements;
3353   if (idSourceToSet(theObject, getMeshDS(), elements, SMDSAbs_All, /*emptyIfIsMesh=*/1))
3354     aGroups = translate(elements, theVector, true, true);
3355
3356   if (!myIsPreviewMode) {
3357     dumpGroupsList(aPythonDump, aGroups);
3358     aPythonDump << this << ".TranslateObjectMakeGroups( "
3359                 << theObject << ", "
3360                 << theVector << " )";
3361   }
3362   return aGroups;
3363 }
3364
3365 //=======================================================================
3366 //function : TranslateMakeMesh
3367 //purpose  :
3368 //=======================================================================
3369
3370 SMESH::SMESH_Mesh_ptr
3371 SMESH_MeshEditor_i::TranslateMakeMesh(const SMESH::long_array& theIDsOfElements,
3372                                       const SMESH::DirStruct&  theVector,
3373                                       CORBA::Boolean           theCopyGroups,
3374                                       const char*              theMeshName)
3375   throw (SALOME::SALOME_Exception)
3376 {
3377   SMESH_Mesh_i* mesh_i;
3378   SMESH::SMESH_Mesh_var mesh;
3379
3380   { // open new scope to dump "MakeMesh" command
3381     // and then "GetGroups" using SMESH_Mesh::GetGroups()
3382
3383     TPythonDump pydump; // to prevent dump at mesh creation
3384
3385     mesh = makeMesh( theMeshName );
3386     mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh );
3387
3388     if ( mesh_i && theIDsOfElements.length() )
3389     {
3390       TIDSortedElemSet elements;
3391       arrayToSet(theIDsOfElements, getMeshDS(), elements);
3392       translate(elements, theVector, false, theCopyGroups, & mesh_i->GetImpl());
3393       mesh_i->CreateGroupServants();
3394     }
3395
3396     if ( !myIsPreviewMode ) {
3397       pydump << mesh << " = " << this << ".TranslateMakeMesh( "
3398              << theIDsOfElements << ", "
3399              << theVector        << ", "
3400              << theCopyGroups    << ", '"
3401              << theMeshName      << "' )";
3402     }
3403   }
3404
3405   //dump "GetGroups"
3406   if (!myIsPreviewMode && mesh_i)
3407     mesh_i->GetGroups();
3408
3409   return mesh._retn();
3410 }
3411
3412 //=======================================================================
3413 //function : TranslateObjectMakeMesh
3414 //purpose  :
3415 //=======================================================================
3416
3417 SMESH::SMESH_Mesh_ptr
3418 SMESH_MeshEditor_i::TranslateObjectMakeMesh(SMESH::SMESH_IDSource_ptr theObject,
3419                                             const SMESH::DirStruct&   theVector,
3420                                             CORBA::Boolean            theCopyGroups,
3421                                             const char*               theMeshName)
3422   throw (SALOME::SALOME_Exception)
3423 {
3424   SMESH_TRY;
3425   SMESH_Mesh_i* mesh_i;
3426   SMESH::SMESH_Mesh_var mesh;
3427   { // open new scope to dump "MakeMesh" command
3428     // and then "GetGroups" using SMESH_Mesh::GetGroups()
3429
3430     TPythonDump pydump; // to prevent dump at mesh creation
3431     mesh = makeMesh( theMeshName );
3432     mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh );
3433
3434     TIDSortedElemSet elements;
3435     if ( mesh_i &&
3436          idSourceToSet(theObject, getMeshDS(), elements, SMDSAbs_All, /*emptyIfIsMesh=*/1))
3437     {
3438       translate(elements, theVector,false, theCopyGroups, & mesh_i->GetImpl());
3439       mesh_i->CreateGroupServants();
3440     }
3441     if ( !myIsPreviewMode ) {
3442       pydump << mesh << " = " << this << ".TranslateObjectMakeMesh( "
3443              << theObject     << ", "
3444              << theVector     << ", "
3445              << theCopyGroups << ", '"
3446              << theMeshName   << "' )";
3447     }
3448   }
3449
3450   // dump "GetGroups"
3451   if (!myIsPreviewMode && mesh_i)
3452     mesh_i->GetGroups();
3453
3454   return mesh._retn();
3455
3456   SMESH_CATCH( SMESH::throwCorbaException );
3457   return 0;
3458 }
3459
3460 //=======================================================================
3461 //function : rotate
3462 //purpose  :
3463 //=======================================================================
3464
3465 SMESH::ListOfGroups*
3466 SMESH_MeshEditor_i::rotate(TIDSortedElemSet &        theElements,
3467                            const SMESH::AxisStruct & theAxis,
3468                            CORBA::Double             theAngle,
3469                            CORBA::Boolean            theCopy,
3470                            bool                      theMakeGroups,
3471                            ::SMESH_Mesh*             theTargetMesh)
3472   throw (SALOME::SALOME_Exception)
3473 {
3474   SMESH_TRY;
3475   initData();
3476
3477   if ( theTargetMesh )
3478     theCopy = false;
3479
3480   gp_Pnt P ( theAxis.x, theAxis.y, theAxis.z );
3481   gp_Vec V ( theAxis.vx, theAxis.vy, theAxis.vz );
3482
3483   gp_Trsf aTrsf;
3484   aTrsf.SetRotation( gp_Ax1( P, V ), theAngle);
3485
3486   TIDSortedElemSet  copyElements;
3487   TIDSortedElemSet* workElements = &theElements;
3488   if ( myIsPreviewMode ) {
3489     TPreviewMesh * tmpMesh = getPreviewMesh();
3490     tmpMesh->Copy( theElements, copyElements );
3491     if ( !theCopy && !theTargetMesh )
3492     {
3493       TIDSortedElemSet elemsAround, elemsAroundCopy;
3494       getElementsAround( theElements, getMeshDS(), elemsAround );
3495       tmpMesh->Copy( elemsAround, elemsAroundCopy);
3496     }
3497     workElements = &copyElements;
3498     theMakeGroups = false;
3499   }
3500
3501   ::SMESH_MeshEditor::PGroupIDs groupIds =
3502       getEditor().Transform (*workElements, aTrsf, theCopy, theMakeGroups, theTargetMesh);
3503
3504   if ( theCopy && !myIsPreviewMode)
3505   {
3506     if ( theTargetMesh ) theTargetMesh->GetMeshDS()->Modified();
3507     else                 declareMeshModified( /*isReComputeSafe=*/false );
3508   }
3509
3510   return theMakeGroups ? getGroups(groupIds.get()) : 0;
3511
3512   SMESH_CATCH( SMESH::throwCorbaException );
3513   return 0;
3514 }
3515
3516 //=======================================================================
3517 //function : Rotate
3518 //purpose  :
3519 //=======================================================================
3520
3521 void SMESH_MeshEditor_i::Rotate(const SMESH::long_array & theIDsOfElements,
3522                                 const SMESH::AxisStruct & theAxis,
3523                                 CORBA::Double             theAngle,
3524                                 CORBA::Boolean            theCopy)
3525   throw (SALOME::SALOME_Exception)
3526 {
3527   if (!myIsPreviewMode) {
3528     TPythonDump() << this << ".Rotate( "
3529                   << theIDsOfElements << ", "
3530                   << theAxis          << ", "
3531                   << TVar( theAngle ) << ", "
3532                   << theCopy          << " )";
3533   }
3534   if (theIDsOfElements.length() > 0)
3535   {
3536     TIDSortedElemSet elements;
3537     arrayToSet(theIDsOfElements, getMeshDS(), elements);
3538     rotate(elements,theAxis,theAngle,theCopy,false);
3539   }
3540 }
3541
3542 //=======================================================================
3543 //function : RotateObject
3544 //purpose  :
3545 //=======================================================================
3546
3547 void SMESH_MeshEditor_i::RotateObject(SMESH::SMESH_IDSource_ptr theObject,
3548                                       const SMESH::AxisStruct & theAxis,
3549                                       CORBA::Double             theAngle,
3550                                       CORBA::Boolean            theCopy)
3551   throw (SALOME::SALOME_Exception)
3552 {
3553   if ( !myIsPreviewMode ) {
3554     TPythonDump() << this << ".RotateObject( "
3555                   << theObject        << ", "
3556                   << theAxis          << ", "
3557                   << TVar( theAngle ) << ", "
3558                   << theCopy          << " )";
3559   }
3560   TIDSortedElemSet elements;
3561   bool emptyIfIsMesh = myIsPreviewMode ? false : true;
3562   if (idSourceToSet(theObject, getMeshDS(), elements, SMDSAbs_All, emptyIfIsMesh))
3563     rotate(elements,theAxis,theAngle,theCopy,false);
3564 }
3565
3566 //=======================================================================
3567 //function : RotateMakeGroups
3568 //purpose  :
3569 //=======================================================================
3570
3571 SMESH::ListOfGroups*
3572 SMESH_MeshEditor_i::RotateMakeGroups(const SMESH::long_array& theIDsOfElements,
3573                                      const SMESH::AxisStruct& theAxis,
3574                                      CORBA::Double            theAngle)
3575   throw (SALOME::SALOME_Exception)
3576 {
3577   TPythonDump aPythonDump; // it is here to prevent dump of GetGroups()
3578
3579   SMESH::ListOfGroups * aGroups = 0;
3580   if (theIDsOfElements.length() > 0)
3581   {
3582     TIDSortedElemSet elements;
3583     arrayToSet(theIDsOfElements, getMeshDS(), elements);
3584     aGroups = rotate(elements,theAxis,theAngle,true,true);
3585   }
3586   if (!myIsPreviewMode) {
3587     dumpGroupsList(aPythonDump, aGroups);
3588     aPythonDump << this << ".RotateMakeGroups( "
3589                 << theIDsOfElements << ", "
3590                 << theAxis          << ", "
3591                 << TVar( theAngle ) << " )";
3592   }
3593   return aGroups;
3594 }
3595
3596 //=======================================================================
3597 //function : RotateObjectMakeGroups
3598 //purpose  :
3599 //=======================================================================
3600
3601 SMESH::ListOfGroups*
3602 SMESH_MeshEditor_i::RotateObjectMakeGroups(SMESH::SMESH_IDSource_ptr theObject,
3603                                            const SMESH::AxisStruct&  theAxis,
3604                                            CORBA::Double             theAngle)
3605   throw (SALOME::SALOME_Exception)
3606 {
3607   TPythonDump aPythonDump; // it is here to prevent dump of GetGroups()
3608
3609   SMESH::ListOfGroups * aGroups = 0;
3610   TIDSortedElemSet elements;
3611   if (idSourceToSet(theObject, getMeshDS(), elements, SMDSAbs_All, /*emptyIfIsMesh=*/1))
3612     aGroups = rotate(elements, theAxis, theAngle, true, true);
3613
3614   if (!myIsPreviewMode) {
3615     dumpGroupsList(aPythonDump, aGroups);
3616     aPythonDump << this << ".RotateObjectMakeGroups( "
3617                 << theObject        << ", "
3618                 << theAxis          << ", "
3619                 << TVar( theAngle ) << " )";
3620   }
3621   return aGroups;
3622 }
3623
3624 //=======================================================================
3625 //function : RotateMakeMesh
3626 //purpose  :
3627 //=======================================================================
3628
3629 SMESH::SMESH_Mesh_ptr
3630 SMESH_MeshEditor_i::RotateMakeMesh(const SMESH::long_array& theIDsOfElements,
3631                                    const SMESH::AxisStruct& theAxis,
3632                                    CORBA::Double            theAngleInRadians,
3633                                    CORBA::Boolean           theCopyGroups,
3634                                    const char*              theMeshName)
3635   throw (SALOME::SALOME_Exception)
3636 {
3637   SMESH_TRY;
3638   SMESH::SMESH_Mesh_var mesh;
3639   SMESH_Mesh_i* mesh_i;
3640
3641   { // open new scope to dump "MakeMesh" command
3642     // and then "GetGroups" using SMESH_Mesh::GetGroups()
3643
3644     TPythonDump pydump; // to prevent dump at mesh creation
3645
3646     mesh = makeMesh( theMeshName );
3647     mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh );
3648
3649     if ( mesh_i && theIDsOfElements.length() > 0 )
3650     {
3651       TIDSortedElemSet elements;
3652       arrayToSet(theIDsOfElements, getMeshDS(), elements);
3653       rotate(elements, theAxis, theAngleInRadians,
3654              false, theCopyGroups, & mesh_i->GetImpl());
3655       mesh_i->CreateGroupServants();
3656     }
3657     if ( !myIsPreviewMode ) {
3658       pydump << mesh << " = " << this << ".RotateMakeMesh( "
3659              << theIDsOfElements          << ", "
3660              << theAxis                   << ", "
3661              << TVar( theAngleInRadians ) << ", "
3662              << theCopyGroups             << ", '"
3663              << theMeshName               << "' )";
3664     }
3665   }
3666
3667   // dump "GetGroups"
3668   if (!myIsPreviewMode && mesh_i && theIDsOfElements.length() > 0 )
3669     mesh_i->GetGroups();
3670
3671   return mesh._retn();
3672
3673   SMESH_CATCH( SMESH::throwCorbaException );
3674   return 0;
3675 }
3676
3677 //=======================================================================
3678 //function : RotateObjectMakeMesh
3679 //purpose  :
3680 //=======================================================================
3681
3682 SMESH::SMESH_Mesh_ptr
3683 SMESH_MeshEditor_i::RotateObjectMakeMesh(SMESH::SMESH_IDSource_ptr theObject,
3684                                          const SMESH::AxisStruct&  theAxis,
3685                                          CORBA::Double             theAngleInRadians,
3686                                          CORBA::Boolean            theCopyGroups,
3687                                          const char*               theMeshName)
3688   throw (SALOME::SALOME_Exception)
3689 {
3690   SMESH_TRY;
3691   SMESH::SMESH_Mesh_var mesh;
3692   SMESH_Mesh_i* mesh_i;
3693
3694   {// open new scope to dump "MakeMesh" command
3695    // and then "GetGroups" using SMESH_Mesh::GetGroups()
3696
3697     TPythonDump pydump; // to prevent dump at mesh creation
3698     mesh = makeMesh( theMeshName );
3699     mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh );
3700
3701     TIDSortedElemSet elements;
3702     if (mesh_i &&
3703         idSourceToSet(theObject, getMeshDS(), elements, SMDSAbs_All, /*emptyIfIsMesh=*/1))
3704     {
3705       rotate(elements, theAxis, theAngleInRadians,
3706              false, theCopyGroups, & mesh_i->GetImpl());
3707       mesh_i->CreateGroupServants();
3708     }
3709     if ( !myIsPreviewMode ) {
3710       pydump << mesh << " = " << this << ".RotateObjectMakeMesh( "
3711              << theObject                 << ", "
3712              << theAxis                   << ", "
3713              << TVar( theAngleInRadians ) << ", "
3714              << theCopyGroups             << ", '"
3715              << theMeshName               << "' )";
3716     }
3717   }
3718
3719   // dump "GetGroups"
3720   if (!myIsPreviewMode && mesh_i)
3721     mesh_i->GetGroups();
3722
3723   return mesh._retn();
3724
3725   SMESH_CATCH( SMESH::throwCorbaException );
3726   return 0;
3727 }
3728
3729 //=======================================================================
3730 //function : scale
3731 //purpose  :
3732 //=======================================================================
3733
3734 SMESH::ListOfGroups*
3735 SMESH_MeshEditor_i::scale(SMESH::SMESH_IDSource_ptr  theObject,
3736                           const SMESH::PointStruct&  thePoint,
3737                           const SMESH::double_array& theScaleFact,
3738                           CORBA::Boolean             theCopy,
3739                           bool                       theMakeGroups,
3740                           ::SMESH_Mesh*              theTargetMesh)
3741   throw (SALOME::SALOME_Exception)
3742 {
3743   SMESH_TRY;
3744   initData();
3745   if ( theScaleFact.length() < 1 )
3746     THROW_SALOME_CORBA_EXCEPTION("Scale factor not given", SALOME::BAD_PARAM);
3747   if ( theScaleFact.length() == 2 )
3748     THROW_SALOME_CORBA_EXCEPTION("Invalid nb of scale factors : 2", SALOME::BAD_PARAM);
3749
3750   if ( theTargetMesh )
3751     theCopy = false;
3752
3753   TIDSortedElemSet elements;
3754   bool emptyIfIsMesh = myIsPreviewMode ? false : true;
3755   if ( !idSourceToSet(theObject, getMeshDS(), elements, SMDSAbs_All, emptyIfIsMesh))
3756     return 0;
3757
3758   double S[3] = {
3759     theScaleFact[0],
3760     (theScaleFact.length() == 1) ? theScaleFact[0] : theScaleFact[1],
3761     (theScaleFact.length() == 1) ? theScaleFact[0] : theScaleFact[2],
3762   };
3763   double tol = std::numeric_limits<double>::max();
3764   gp_Trsf aTrsf;
3765
3766 #if OCC_VERSION_LARGE > 0x06070100
3767   // fight against ortagonalization
3768   // aTrsf.SetValues( S[0], 0,    0,    thePoint.x * (1-S[0]),
3769   //                  0,    S[1], 0,    thePoint.y * (1-S[1]),
3770   //                  0,    0,    S[2], thePoint.z * (1-S[2]) );
3771   aTrsf.SetTranslation( gp_Vec( thePoint.x * (1-S[0]),
3772                                 thePoint.y * (1-S[1]),
3773                                 thePoint.z * (1-S[2])));
3774   gp_Mat & M = ( gp_Mat& ) aTrsf.HVectorialPart();
3775   M.SetDiagonal( S[0], S[1], S[2] );
3776
3777 #else
3778   aTrsf.SetValues( S[0], 0,    0,    thePoint.x * (1-S[0]),
3779                    0,    S[1], 0,    thePoint.y * (1-S[1]),
3780                    0,    0,    S[2], thePoint.z * (1-S[2]),   tol, tol);
3781 #endif
3782
3783   TIDSortedElemSet  copyElements;
3784   TIDSortedElemSet* workElements = &elements;
3785   if ( myIsPreviewMode )
3786   {
3787     TPreviewMesh * tmpMesh = getPreviewMesh();
3788     tmpMesh->Copy( elements, copyElements);
3789     if ( !theCopy && !theTargetMesh )
3790     {
3791       TIDSortedElemSet elemsAround, elemsAroundCopy;
3792       getElementsAround( elements, getMeshDS(), elemsAround );
3793       tmpMesh->Copy( elemsAround, elemsAroundCopy);
3794     }
3795     workElements = & copyElements;
3796     theMakeGroups = false;
3797   }
3798
3799   ::SMESH_MeshEditor::PGroupIDs groupIds =
3800       getEditor().Transform (*workElements, aTrsf, theCopy, theMakeGroups, theTargetMesh);
3801
3802   if ( theCopy && !myIsPreviewMode )
3803   {
3804     if ( theTargetMesh ) theTargetMesh->GetMeshDS()->Modified();
3805     else                 declareMeshModified( /*isReComputeSafe=*/false );
3806   }
3807   return theMakeGroups ? getGroups(groupIds.get()) : 0;
3808
3809   SMESH_CATCH( SMESH::throwCorbaException );
3810   return 0;
3811 }
3812
3813 //=======================================================================
3814 //function : Scale
3815 //purpose  :
3816 //=======================================================================
3817
3818 void SMESH_MeshEditor_i::Scale(SMESH::SMESH_IDSource_ptr  theObject,
3819                                const SMESH::PointStruct&  thePoint,
3820                                const SMESH::double_array& theScaleFact,
3821                                CORBA::Boolean             theCopy)
3822   throw (SALOME::SALOME_Exception)
3823 {
3824   if ( !myIsPreviewMode ) {
3825     TPythonDump() << this << ".Scale( "
3826                   << theObject            << ", "
3827                   << thePoint             << ", "
3828                   << TVar( theScaleFact ) << ", "
3829                   << theCopy              << " )";
3830   }
3831   scale(theObject, thePoint, theScaleFact, theCopy, false);
3832 }
3833
3834
3835 //=======================================================================
3836 //function : ScaleMakeGroups
3837 //purpose  :
3838 //=======================================================================
3839
3840 SMESH::ListOfGroups*
3841 SMESH_MeshEditor_i::ScaleMakeGroups(SMESH::SMESH_IDSource_ptr  theObject,
3842                                     const SMESH::PointStruct&  thePoint,
3843                                     const SMESH::double_array& theScaleFact)
3844   throw (SALOME::SALOME_Exception)
3845 {
3846   TPythonDump aPythonDump; // it is here to prevent dump of GetGroups()
3847
3848   SMESH::ListOfGroups * aGroups = scale(theObject, thePoint, theScaleFact, true, true);
3849   if (!myIsPreviewMode) {
3850     dumpGroupsList(aPythonDump, aGroups);
3851     aPythonDump << this << ".Scale("
3852                 << theObject            << ","
3853                 << thePoint             << ","
3854                 << TVar( theScaleFact ) << ",True,True)";
3855   }
3856   return aGroups;
3857 }
3858
3859
3860 //=======================================================================
3861 //function : ScaleMakeMesh
3862 //purpose  :
3863 //=======================================================================
3864
3865 SMESH::SMESH_Mesh_ptr
3866 SMESH_MeshEditor_i::ScaleMakeMesh(SMESH::SMESH_IDSource_ptr  theObject,
3867                                   const SMESH::PointStruct&  thePoint,
3868                                   const SMESH::double_array& theScaleFact,
3869                                   CORBA::Boolean             theCopyGroups,
3870                                   const char*                theMeshName)
3871   throw (SALOME::SALOME_Exception)
3872 {
3873   SMESH_Mesh_i* mesh_i;
3874   SMESH::SMESH_Mesh_var mesh;
3875   { // open new scope to dump "MakeMesh" command
3876     // and then "GetGroups" using SMESH_Mesh::GetGroups()
3877
3878     TPythonDump pydump; // to prevent dump at mesh creation
3879     mesh = makeMesh( theMeshName );
3880     mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh );
3881
3882     if ( mesh_i )
3883     {
3884       scale(theObject, thePoint, theScaleFact,false, theCopyGroups, & mesh_i->GetImpl());
3885       mesh_i->CreateGroupServants();
3886     }
3887     if ( !myIsPreviewMode )
3888       pydump << mesh << " = " << this << ".ScaleMakeMesh( "
3889              << theObject            << ", "
3890              << thePoint             << ", "
3891              << TVar( theScaleFact ) << ", "
3892              << theCopyGroups        << ", '"
3893              << theMeshName          << "' )";
3894   }
3895
3896   // dump "GetGroups"
3897   if (!myIsPreviewMode && mesh_i)
3898     mesh_i->GetGroups();
3899
3900   return mesh._retn();
3901 }
3902
3903
3904 //=======================================================================
3905 //function : FindCoincidentNodes
3906 //purpose  :
3907 //=======================================================================
3908
3909 void SMESH_MeshEditor_i::FindCoincidentNodes (CORBA::Double                  Tolerance,
3910                                               SMESH::array_of_long_array_out GroupsOfNodes)
3911   throw (SALOME::SALOME_Exception)
3912 {
3913   SMESH_TRY;
3914   initData();
3915
3916   ::SMESH_MeshEditor::TListOfListOfNodes aListOfListOfNodes;
3917   TIDSortedNodeSet nodes; // no input nodes
3918   getEditor().FindCoincidentNodes( nodes, Tolerance, aListOfListOfNodes );
3919
3920   GroupsOfNodes = new SMESH::array_of_long_array;
3921   GroupsOfNodes->length( aListOfListOfNodes.size() );
3922   ::SMESH_MeshEditor::TListOfListOfNodes::iterator llIt = aListOfListOfNodes.begin();
3923   for ( CORBA::Long i = 0; llIt != aListOfListOfNodes.end(); llIt++, i++ ) {
3924     list< const SMDS_MeshNode* >& aListOfNodes = *llIt;
3925     list< const SMDS_MeshNode* >::iterator lIt = aListOfNodes.begin();;
3926     SMESH::long_array& aGroup = (*GroupsOfNodes)[ i ];
3927     aGroup.length( aListOfNodes.size() );
3928     for ( int j = 0; lIt != aListOfNodes.end(); lIt++, j++ )
3929       aGroup[ j ] = (*lIt)->GetID();
3930   }
3931   TPythonDump() << "coincident_nodes = " << this << ".FindCoincidentNodes( "
3932                 << Tolerance << " )";
3933
3934   SMESH_CATCH( SMESH::throwCorbaException );
3935 }
3936
3937 //=======================================================================
3938 //function : FindCoincidentNodesOnPart
3939 //purpose  :
3940 //=======================================================================
3941
3942 void SMESH_MeshEditor_i::FindCoincidentNodesOnPart(SMESH::SMESH_IDSource_ptr      theObject,
3943                                                    CORBA::Double                  Tolerance,
3944                                                    SMESH::array_of_long_array_out GroupsOfNodes)
3945   throw (SALOME::SALOME_Exception)
3946 {
3947   SMESH_TRY;
3948   initData();
3949
3950   TIDSortedNodeSet nodes;
3951   idSourceToNodeSet( theObject, getMeshDS(), nodes );
3952
3953   ::SMESH_MeshEditor::TListOfListOfNodes aListOfListOfNodes;
3954   if(!nodes.empty())
3955     getEditor().FindCoincidentNodes( nodes, Tolerance, aListOfListOfNodes );
3956
3957   GroupsOfNodes = new SMESH::array_of_long_array;
3958   GroupsOfNodes->length( aListOfListOfNodes.size() );
3959   ::SMESH_MeshEditor::TListOfListOfNodes::iterator llIt = aListOfListOfNodes.begin();
3960   for ( CORBA::Long i = 0; llIt != aListOfListOfNodes.end(); llIt++, i++ )
3961   {
3962     list< const SMDS_MeshNode* >& aListOfNodes = *llIt;
3963     list< const SMDS_MeshNode* >::iterator lIt = aListOfNodes.begin();;
3964     SMESH::long_array& aGroup = (*GroupsOfNodes)[ i ];
3965     aGroup.length( aListOfNodes.size() );
3966     for ( int j = 0; lIt != aListOfNodes.end(); lIt++, j++ )
3967       aGroup[ j ] = (*lIt)->GetID();
3968   }
3969   TPythonDump() << "coincident_nodes_on_part = " << this << ".FindCoincidentNodesOnPart( "
3970                 <<theObject<<", "
3971                 << Tolerance << " )";
3972
3973   SMESH_CATCH( SMESH::throwCorbaException );
3974 }
3975
3976 //================================================================================
3977 /*!
3978  * \brief Finds nodes coinsident with Tolerance within Object excluding nodes within
3979  *        ExceptSubMeshOrGroups
3980  */
3981 //================================================================================
3982
3983 void SMESH_MeshEditor_i::
3984 FindCoincidentNodesOnPartBut(SMESH::SMESH_IDSource_ptr      theObject,
3985                              CORBA::Double                  theTolerance,
3986                              SMESH::array_of_long_array_out theGroupsOfNodes,
3987                              const SMESH::ListOfIDSources&  theExceptSubMeshOrGroups)
3988   throw (SALOME::SALOME_Exception)
3989 {
3990   SMESH_TRY;
3991   initData();
3992
3993   TIDSortedNodeSet nodes;
3994   idSourceToNodeSet( theObject, getMeshDS(), nodes );
3995
3996   for ( int i = 0; i < theExceptSubMeshOrGroups.length(); ++i )
3997   {
3998     TIDSortedNodeSet exceptNodes;
3999     idSourceToNodeSet( theExceptSubMeshOrGroups[i], getMeshDS(), exceptNodes );
4000     TIDSortedNodeSet::iterator avoidNode = exceptNodes.begin();
4001     for ( ; avoidNode != exceptNodes.end(); ++avoidNode)
4002       nodes.erase( *avoidNode );
4003   }
4004   ::SMESH_MeshEditor::TListOfListOfNodes aListOfListOfNodes;
4005   if(!nodes.empty())
4006     getEditor().FindCoincidentNodes( nodes, theTolerance, aListOfListOfNodes );
4007
4008   theGroupsOfNodes = new SMESH::array_of_long_array;
4009   theGroupsOfNodes->length( aListOfListOfNodes.size() );
4010   ::SMESH_MeshEditor::TListOfListOfNodes::iterator llIt = aListOfListOfNodes.begin();
4011   for ( CORBA::Long i = 0; llIt != aListOfListOfNodes.end(); llIt++, i++ )
4012   {
4013     list< const SMDS_MeshNode* >& aListOfNodes = *llIt;
4014     list< const SMDS_MeshNode* >::iterator lIt = aListOfNodes.begin();;
4015     SMESH::long_array& aGroup = (*theGroupsOfNodes)[ i ];
4016     aGroup.length( aListOfNodes.size() );
4017     for ( int j = 0; lIt != aListOfNodes.end(); lIt++, j++ )
4018       aGroup[ j ] = (*lIt)->GetID();
4019   }
4020   TPythonDump() << "coincident_nodes_on_part = " << this << ".FindCoincidentNodesOnPartBut( "
4021                 << theObject<<", "
4022                 << theTolerance << ", "
4023                 << theExceptSubMeshOrGroups << " )";
4024
4025   SMESH_CATCH( SMESH::throwCorbaException );
4026 }
4027
4028 //=======================================================================
4029 //function : MergeNodes
4030 //purpose  :
4031 //=======================================================================
4032
4033 void SMESH_MeshEditor_i::MergeNodes (const SMESH::array_of_long_array& GroupsOfNodes)
4034   throw (SALOME::SALOME_Exception)
4035 {
4036   SMESH_TRY;
4037   initData();
4038
4039   SMESHDS_Mesh* aMesh = getMeshDS();
4040
4041   TPythonDump aTPythonDump;
4042   aTPythonDump << this << ".MergeNodes([";
4043   ::SMESH_MeshEditor::TListOfListOfNodes aListOfListOfNodes;
4044   for (int i = 0; i < GroupsOfNodes.length(); i++)
4045   {
4046     const SMESH::long_array& aNodeGroup = GroupsOfNodes[ i ];
4047     aListOfListOfNodes.push_back( list< const SMDS_MeshNode* >() );
4048     list< const SMDS_MeshNode* >& aListOfNodes = aListOfListOfNodes.back();
4049     for ( int j = 0; j < aNodeGroup.length(); j++ )
4050     {
4051       CORBA::Long index = aNodeGroup[ j ];
4052       const SMDS_MeshNode * node = aMesh->FindNode(index);
4053       if ( node )
4054         aListOfNodes.push_back( node );
4055     }
4056     if ( aListOfNodes.size() < 2 )
4057       aListOfListOfNodes.pop_back();
4058
4059     if ( i > 0 ) aTPythonDump << ", ";
4060     aTPythonDump << aNodeGroup;
4061   }
4062   getEditor().MergeNodes( aListOfListOfNodes );
4063
4064   aTPythonDump <<  "])";
4065
4066   declareMeshModified( /*isReComputeSafe=*/false );
4067
4068   SMESH_CATCH( SMESH::throwCorbaException );
4069 }
4070
4071 //=======================================================================
4072 //function : FindEqualElements
4073 //purpose  :
4074 //=======================================================================
4075
4076 void SMESH_MeshEditor_i::FindEqualElements(SMESH::SMESH_IDSource_ptr      theObject,
4077                                            SMESH::array_of_long_array_out GroupsOfElementsID)
4078   throw (SALOME::SALOME_Exception)
4079 {
4080   SMESH_TRY;
4081   initData();
4082
4083   SMESH::SMESH_GroupBase_var group = SMESH::SMESH_GroupBase::_narrow(theObject);
4084   if ( !(!group->_is_nil() && group->GetType() == SMESH::NODE) )
4085   {
4086     TIDSortedElemSet elems;
4087     idSourceToSet( theObject, getMeshDS(), elems, SMDSAbs_All, /*emptyIfIsMesh=*/true);
4088
4089     ::SMESH_MeshEditor::TListOfListOfElementsID aListOfListOfElementsID;
4090     getEditor().FindEqualElements( elems, aListOfListOfElementsID );
4091
4092     GroupsOfElementsID = new SMESH::array_of_long_array;
4093     GroupsOfElementsID->length( aListOfListOfElementsID.size() );
4094
4095     ::SMESH_MeshEditor::TListOfListOfElementsID::iterator arraysIt =
4096         aListOfListOfElementsID.begin();
4097     for (CORBA::Long j = 0; arraysIt != aListOfListOfElementsID.end(); ++arraysIt, ++j)
4098     {
4099       SMESH::long_array& aGroup = (*GroupsOfElementsID)[ j ];
4100       list<int>&      listOfIDs = *arraysIt;
4101       aGroup.length( listOfIDs.size() );
4102       list<int>::iterator idIt = listOfIDs.begin();
4103       for (int k = 0; idIt != listOfIDs.end(); ++idIt, ++k )
4104         aGroup[ k ] = *idIt;
4105     }
4106
4107     TPythonDump() << "equal_elements = " << this << ".FindEqualElements( "
4108                   <<theObject<<" )";
4109   }
4110
4111   SMESH_CATCH( SMESH::throwCorbaException );
4112 }
4113
4114 //=======================================================================
4115 //function : MergeElements
4116 //purpose  :
4117 //=======================================================================
4118
4119 void SMESH_MeshEditor_i::MergeElements(const SMESH::array_of_long_array& GroupsOfElementsID)
4120   throw (SALOME::SALOME_Exception)
4121 {
4122   SMESH_TRY;
4123   initData();
4124
4125   TPythonDump aTPythonDump;
4126   aTPythonDump << this << ".MergeElements( [";
4127
4128   ::SMESH_MeshEditor::TListOfListOfElementsID aListOfListOfElementsID;
4129
4130   for (int i = 0; i < GroupsOfElementsID.length(); i++) {
4131     const SMESH::long_array& anElemsIDGroup = GroupsOfElementsID[ i ];
4132     aListOfListOfElementsID.push_back( list< int >() );
4133     list< int >& aListOfElemsID = aListOfListOfElementsID.back();
4134     for ( int j = 0; j < anElemsIDGroup.length(); j++ ) {
4135       CORBA::Long id = anElemsIDGroup[ j ];
4136       aListOfElemsID.push_back( id );
4137     }
4138     if ( aListOfElemsID.size() < 2 )
4139       aListOfListOfElementsID.pop_back();
4140     if ( i > 0 ) aTPythonDump << ", ";
4141     aTPythonDump << anElemsIDGroup;
4142   }
4143
4144   getEditor().MergeElements(aListOfListOfElementsID);
4145
4146   declareMeshModified( /*isReComputeSafe=*/true );
4147
4148   aTPythonDump << "] )";
4149
4150   SMESH_CATCH( SMESH::throwCorbaException );
4151 }
4152
4153 //=======================================================================
4154 //function : MergeEqualElements
4155 //purpose  :
4156 //=======================================================================
4157
4158 void SMESH_MeshEditor_i::MergeEqualElements()
4159   throw (SALOME::SALOME_Exception)
4160 {
4161   SMESH_TRY;
4162   initData();
4163
4164   getEditor().MergeEqualElements();
4165
4166   declareMeshModified( /*isReComputeSafe=*/true );
4167
4168   TPythonDump() << this << ".MergeEqualElements()";
4169
4170   SMESH_CATCH( SMESH::throwCorbaException );
4171 }
4172
4173 //=============================================================================
4174 /*!
4175  * Move the node to a given point
4176  */
4177 //=============================================================================
4178
4179 CORBA::Boolean SMESH_MeshEditor_i::MoveNode(CORBA::Long   NodeID,
4180                                             CORBA::Double x,
4181                                             CORBA::Double y,
4182                                             CORBA::Double z)
4183   throw (SALOME::SALOME_Exception)
4184 {
4185   SMESH_TRY;
4186   initData(/*deleteSearchers=*/false);
4187
4188   const SMDS_MeshNode * node = getMeshDS()->FindNode( NodeID );
4189   if ( !node )
4190     return false;
4191
4192   if ( theNodeSearcher )
4193     theSearchersDeleter.Set( myMesh ); // remove theNodeSearcher if mesh is other
4194
4195   if ( myIsPreviewMode ) // make preview data
4196   {
4197     // in a preview mesh, make edges linked to a node
4198     TPreviewMesh& tmpMesh = *getPreviewMesh();
4199     TIDSortedElemSet linkedNodes;
4200     ::SMESH_MeshEditor::GetLinkedNodes( node, linkedNodes );
4201     TIDSortedElemSet::iterator nIt = linkedNodes.begin();
4202     SMDS_MeshNode *nodeCpy1 = tmpMesh.Copy(node);
4203     for ( ; nIt != linkedNodes.end(); ++nIt )
4204     {
4205       SMDS_MeshNode *nodeCpy2 = tmpMesh.Copy ( cast2Node( *nIt ));
4206       tmpMesh.GetMeshDS()->AddEdge(nodeCpy1, nodeCpy2);
4207     }
4208     // move copied node
4209     if ( nodeCpy1 )
4210       tmpMesh.GetMeshDS()->MoveNode(nodeCpy1, x, y, z);
4211     // fill preview data
4212   }
4213   else if ( theNodeSearcher ) // move node and update theNodeSearcher data accordingly
4214     theNodeSearcher->MoveNode(node, gp_Pnt( x,y,z ));
4215   else
4216     getMeshDS()->MoveNode(node, x, y, z);
4217
4218   if ( !myIsPreviewMode )
4219   {
4220     // Update Python script
4221     TPythonDump() << "isDone = " << this << ".MoveNode( "
4222                   << NodeID << ", " << TVar(x) << ", " << TVar(y) << ", " << TVar(z) << " )";
4223     declareMeshModified( /*isReComputeSafe=*/false );
4224   }
4225
4226   SMESH_CATCH( SMESH::throwCorbaException );
4227
4228   return true;
4229 }
4230
4231 //================================================================================
4232 /*!
4233  * \brief Return ID of node closest to a given point
4234  */
4235 //================================================================================
4236
4237 CORBA::Long SMESH_MeshEditor_i::FindNodeClosestTo(CORBA::Double x,
4238                                                   CORBA::Double y,
4239                                                   CORBA::Double z)
4240   throw (SALOME::SALOME_Exception)
4241 {
4242   SMESH_TRY;
4243   theSearchersDeleter.Set( myMesh ); // remove theNodeSearcher if mesh is other
4244
4245   if ( !theNodeSearcher ) {
4246     theNodeSearcher = SMESH_MeshAlgos::GetNodeSearcher( *getMeshDS() );
4247   }
4248   gp_Pnt p( x,y,z );
4249   if ( const SMDS_MeshNode* node = theNodeSearcher->FindClosestTo( p ))
4250     return node->GetID();
4251
4252   SMESH_CATCH( SMESH::throwCorbaException );
4253   return 0;
4254 }
4255
4256 //================================================================================
4257 /*!
4258  * \brief If the given ID is a valid node ID (nodeID > 0), just move this node, else
4259  * move the node closest to the point to point's location and return ID of the node
4260  */
4261 //================================================================================
4262
4263 CORBA::Long SMESH_MeshEditor_i::MoveClosestNodeToPoint(CORBA::Double x,
4264                                                        CORBA::Double y,
4265                                                        CORBA::Double z,
4266                                                        CORBA::Long   theNodeID)
4267   throw (SALOME::SALOME_Exception)
4268 {
4269   SMESH_TRY;
4270   // We keep theNodeSearcher until any mesh modification:
4271   // 1) initData() deletes theNodeSearcher at any edition,
4272   // 2) TSearchersDeleter - at any mesh compute event and mesh change
4273
4274   initData(/*deleteSearchers=*/false);
4275
4276   theSearchersDeleter.Set( myMesh ); // remove theNodeSearcher if mesh is other
4277
4278   int nodeID = theNodeID;
4279   const SMDS_MeshNode* node = getMeshDS()->FindNode( nodeID );
4280   if ( !node ) // preview moving node
4281   {
4282     if ( !theNodeSearcher ) {
4283       theNodeSearcher = SMESH_MeshAlgos::GetNodeSearcher( *getMeshDS() );
4284     }
4285     gp_Pnt p( x,y,z );
4286     node = theNodeSearcher->FindClosestTo( p );
4287   }
4288   if ( node ) {
4289     nodeID = node->GetID();
4290     if ( myIsPreviewMode ) // make preview data
4291     {
4292       // in a preview mesh, make edges linked to a node
4293       TPreviewMesh tmpMesh = *getPreviewMesh();
4294       TIDSortedElemSet linkedNodes;
4295       ::SMESH_MeshEditor::GetLinkedNodes( node, linkedNodes );
4296       TIDSortedElemSet::iterator nIt = linkedNodes.begin();
4297       for ( ; nIt != linkedNodes.end(); ++nIt )
4298       {
4299         SMDS_LinearEdge edge( node, cast2Node( *nIt ));
4300         tmpMesh.Copy( &edge );
4301       }
4302       // move copied node
4303       node = tmpMesh.GetMeshDS()->FindNode( nodeID );
4304       if ( node )
4305         tmpMesh.GetMeshDS()->MoveNode(node, x, y, z);
4306       // fill preview data
4307     }
4308     else if ( theNodeSearcher ) // move node and update theNodeSearcher data accordingly
4309     {
4310       theNodeSearcher->MoveNode(node, gp_Pnt( x,y,z ));
4311     }
4312     else
4313     {
4314       getMeshDS()->MoveNode(node, x, y, z);
4315     }
4316   }
4317
4318   if ( !myIsPreviewMode )
4319   {
4320     TPythonDump() << "nodeID = " << this
4321                   << ".MoveClosestNodeToPoint( "<< x << ", " << y << ", " << z
4322                   << ", " << nodeID << " )";
4323
4324     declareMeshModified( /*isReComputeSafe=*/false );
4325   }
4326
4327   return nodeID;
4328
4329   SMESH_CATCH( SMESH::throwCorbaException );
4330   return 0;
4331 }
4332
4333 //=======================================================================
4334 /*!
4335  * Return elements of given type where the given point is IN or ON.
4336  *
4337  * 'ALL' type means elements of any type excluding nodes
4338  */
4339 //=======================================================================
4340
4341 SMESH::long_array* SMESH_MeshEditor_i::FindElementsByPoint(CORBA::Double      x,
4342                                                            CORBA::Double      y,
4343                                                            CORBA::Double      z,
4344                                                            SMESH::ElementType type)
4345   throw (SALOME::SALOME_Exception)
4346 {
4347   SMESH_TRY;
4348   SMESH::long_array_var res = new SMESH::long_array;
4349   vector< const SMDS_MeshElement* > foundElems;
4350
4351   theSearchersDeleter.Set( myMesh );
4352   if ( !theElementSearcher ) {
4353     theElementSearcher = SMESH_MeshAlgos::GetElementSearcher( *getMeshDS() );
4354   }
4355   theElementSearcher->FindElementsByPoint( gp_Pnt( x,y,z ),
4356                                            SMDSAbs_ElementType( type ),
4357                                            foundElems);
4358   res->length( foundElems.size() );
4359   for ( int i = 0; i < foundElems.size(); ++i )
4360     res[i] = foundElems[i]->GetID();
4361
4362   return res._retn();
4363
4364   SMESH_CATCH( SMESH::throwCorbaException );
4365   return 0;
4366 }
4367
4368 //=======================================================================
4369 //function : FindAmongElementsByPoint
4370 //purpose  : Searching among the given elements, return elements of given type 
4371 //           where the given point is IN or ON.
4372 //           'ALL' type means elements of any type excluding nodes
4373 //=======================================================================
4374
4375 SMESH::long_array*
4376 SMESH_MeshEditor_i::FindAmongElementsByPoint(SMESH::SMESH_IDSource_ptr elementIDs,
4377                                              CORBA::Double             x,
4378                                              CORBA::Double             y,
4379                                              CORBA::Double             z,
4380                                              SMESH::ElementType        type)
4381   throw (SALOME::SALOME_Exception)
4382 {
4383   SMESH_TRY;
4384   SMESH::long_array_var res = new SMESH::long_array;
4385   
4386   SMESH::array_of_ElementType_var types = elementIDs->GetTypes();
4387   if ( types->length() == 1 && // a part contains only nodes or 0D elements
4388        ( types[0] == SMESH::NODE || types[0] == SMESH::ELEM0D || types[0] == SMESH::BALL) &&
4389        type != types[0] ) // but search of elements of dim > 0
4390     return res._retn();
4391
4392   if ( SMESH::DownCast<SMESH_Mesh_i*>( elementIDs )) // elementIDs is the whole mesh 
4393     return FindElementsByPoint( x,y,z, type );
4394
4395   TIDSortedElemSet elements; // elems should live until FindElementsByPoint() finishes
4396
4397   theSearchersDeleter.Set( myMesh, getPartIOR( elementIDs, type ));
4398   if ( !theElementSearcher )
4399   {
4400     // create a searcher from elementIDs
4401     SMESH::SMESH_Mesh_var mesh = elementIDs->GetMesh();
4402     SMESHDS_Mesh* meshDS = SMESH::DownCast<SMESH_Mesh_i*>( mesh )->GetImpl().GetMeshDS();
4403
4404     if ( !idSourceToSet( elementIDs, meshDS, elements,
4405                          SMDSAbs_ElementType(type), /*emptyIfIsMesh=*/true))
4406       return res._retn();
4407
4408     typedef SMDS_SetIterator<const SMDS_MeshElement*, TIDSortedElemSet::const_iterator > TIter;
4409     SMDS_ElemIteratorPtr elemsIt( new TIter( elements.begin(), elements.end() ));
4410
4411     theElementSearcher = SMESH_MeshAlgos::GetElementSearcher( *getMeshDS(), elemsIt );
4412   }
4413
4414   vector< const SMDS_MeshElement* > foundElems;
4415
4416   theElementSearcher->FindElementsByPoint( gp_Pnt( x,y,z ),
4417                                            SMDSAbs_ElementType( type ),
4418                                            foundElems);
4419   res->length( foundElems.size() );
4420   for ( int i = 0; i < foundElems.size(); ++i )
4421     res[i] = foundElems[i]->GetID();
4422
4423   return res._retn();
4424
4425   SMESH_CATCH( SMESH::throwCorbaException );
4426   return 0;
4427 }
4428
4429 //=======================================================================
4430 //function : GetPointState
4431 //purpose  : Return point state in a closed 2D mesh in terms of TopAbs_State enumeration.
4432 //           TopAbs_UNKNOWN state means that either mesh is wrong or the analysis fails.
4433 //=======================================================================
4434
4435 CORBA::Short SMESH_MeshEditor_i::GetPointState(CORBA::Double x,
4436                                                CORBA::Double y,
4437                                                CORBA::Double z)
4438   throw (SALOME::SALOME_Exception)
4439 {
4440   SMESH_TRY;
4441   theSearchersDeleter.Set( myMesh );
4442   if ( !theElementSearcher ) {
4443     theElementSearcher = SMESH_MeshAlgos::GetElementSearcher( *getMeshDS() );
4444   }
4445   return CORBA::Short( theElementSearcher->GetPointState( gp_Pnt( x,y,z )));
4446
4447   SMESH_CATCH( SMESH::throwCorbaException );
4448   return 0;
4449 }
4450
4451 //=======================================================================
4452 //function : convError
4453 //purpose  :
4454 //=======================================================================
4455
4456 #define RETCASE(enm) case ::SMESH_MeshEditor::enm: return SMESH::SMESH_MeshEditor::enm;
4457
4458 static SMESH::SMESH_MeshEditor::Sew_Error convError( const::SMESH_MeshEditor::Sew_Error e )
4459 {
4460   switch ( e ) {
4461     RETCASE( SEW_OK );
4462     RETCASE( SEW_BORDER1_NOT_FOUND );
4463     RETCASE( SEW_BORDER2_NOT_FOUND );
4464     RETCASE( SEW_BOTH_BORDERS_NOT_FOUND );
4465     RETCASE( SEW_BAD_SIDE_NODES );
4466     RETCASE( SEW_VOLUMES_TO_SPLIT );
4467     RETCASE( SEW_DIFF_NB_OF_ELEMENTS );
4468     RETCASE( SEW_TOPO_DIFF_SETS_OF_ELEMENTS );
4469     RETCASE( SEW_BAD_SIDE1_NODES );
4470     RETCASE( SEW_BAD_SIDE2_NODES );
4471   }
4472   return SMESH::SMESH_MeshEditor::SEW_OK;
4473 }
4474
4475 //=======================================================================
4476 //function : SewFreeBorders
4477 //purpose  :
4478 //=======================================================================
4479
4480 SMESH::SMESH_MeshEditor::Sew_Error
4481 SMESH_MeshEditor_i::SewFreeBorders(CORBA::Long FirstNodeID1,
4482                                    CORBA::Long SecondNodeID1,
4483                                    CORBA::Long LastNodeID1,
4484                                    CORBA::Long FirstNodeID2,
4485                                    CORBA::Long SecondNodeID2,
4486                                    CORBA::Long LastNodeID2,
4487                                    CORBA::Boolean CreatePolygons,
4488                                    CORBA::Boolean CreatePolyedrs)
4489   throw (SALOME::SALOME_Exception)
4490 {
4491   SMESH_TRY;
4492   initData();
4493
4494   SMESHDS_Mesh* aMesh = getMeshDS();
4495
4496   const SMDS_MeshNode* aBorderFirstNode  = aMesh->FindNode( FirstNodeID1  );
4497   const SMDS_MeshNode* aBorderSecondNode = aMesh->FindNode( SecondNodeID1 );
4498   const SMDS_MeshNode* aBorderLastNode   = aMesh->FindNode( LastNodeID1   );
4499   const SMDS_MeshNode* aSide2FirstNode   = aMesh->FindNode( FirstNodeID2  );
4500   const SMDS_MeshNode* aSide2SecondNode  = aMesh->FindNode( SecondNodeID2 );
4501   const SMDS_MeshNode* aSide2ThirdNode   = aMesh->FindNode( LastNodeID2   );
4502
4503   if (!aBorderFirstNode ||
4504       !aBorderSecondNode||
4505       !aBorderLastNode)
4506     return SMESH::SMESH_MeshEditor::SEW_BORDER1_NOT_FOUND;
4507   if (!aSide2FirstNode  ||
4508       !aSide2SecondNode ||
4509       !aSide2ThirdNode)
4510     return SMESH::SMESH_MeshEditor::SEW_BORDER2_NOT_FOUND;
4511
4512   TPythonDump() << "error = " << this << ".SewFreeBorders( "
4513                 << FirstNodeID1  << ", "
4514                 << SecondNodeID1 << ", "
4515                 << LastNodeID1   << ", "
4516                 << FirstNodeID2  << ", "
4517                 << SecondNodeID2 << ", "
4518                 << LastNodeID2   << ", "
4519                 << CreatePolygons<< ", "
4520                 << CreatePolyedrs<< " )";
4521
4522   SMESH::SMESH_MeshEditor::Sew_Error error =
4523     convError( getEditor().SewFreeBorder (aBorderFirstNode,
4524                                        aBorderSecondNode,
4525                                        aBorderLastNode,
4526                                        aSide2FirstNode,
4527                                        aSide2SecondNode,
4528                                        aSide2ThirdNode,
4529                                        true,
4530                                        CreatePolygons,
4531                                        CreatePolyedrs) );
4532
4533
4534   declareMeshModified( /*isReComputeSafe=*/false );
4535   return error;
4536
4537   SMESH_CATCH( SMESH::throwCorbaException );
4538   return SMESH::SMESH_MeshEditor::Sew_Error(0);
4539 }
4540
4541
4542 //=======================================================================
4543 //function : SewConformFreeBorders
4544 //purpose  :
4545 //=======================================================================
4546
4547 SMESH::SMESH_MeshEditor::Sew_Error
4548 SMESH_MeshEditor_i::SewConformFreeBorders(CORBA::Long FirstNodeID1,
4549                                           CORBA::Long SecondNodeID1,
4550                                           CORBA::Long LastNodeID1,
4551                                           CORBA::Long FirstNodeID2,
4552                                           CORBA::Long SecondNodeID2)
4553   throw (SALOME::SALOME_Exception)
4554 {
4555   SMESH_TRY;
4556   initData();
4557
4558   SMESHDS_Mesh* aMesh = getMeshDS();
4559
4560   const SMDS_MeshNode* aBorderFirstNode  = aMesh->FindNode( FirstNodeID1  );
4561   const SMDS_MeshNode* aBorderSecondNode = aMesh->FindNode( SecondNodeID1 );
4562   const SMDS_MeshNode* aBorderLastNode   = aMesh->FindNode( LastNodeID1   );
4563   const SMDS_MeshNode* aSide2FirstNode   = aMesh->FindNode( FirstNodeID2  );
4564   const SMDS_MeshNode* aSide2SecondNode  = aMesh->FindNode( SecondNodeID2 );
4565   const SMDS_MeshNode* aSide2ThirdNode   = 0;
4566
4567   if (!aBorderFirstNode ||
4568       !aBorderSecondNode||
4569       !aBorderLastNode )
4570     return SMESH::SMESH_MeshEditor::SEW_BORDER1_NOT_FOUND;
4571   if (!aSide2FirstNode  ||
4572       !aSide2SecondNode)
4573     return SMESH::SMESH_MeshEditor::SEW_BORDER2_NOT_FOUND;
4574
4575   TPythonDump() << "error = " << this << ".SewConformFreeBorders( "
4576                 << FirstNodeID1  << ", "
4577                 << SecondNodeID1 << ", "
4578                 << LastNodeID1   << ", "
4579                 << FirstNodeID2  << ", "
4580                 << SecondNodeID2 << " )";
4581
4582   SMESH::SMESH_MeshEditor::Sew_Error error =
4583     convError( getEditor().SewFreeBorder (aBorderFirstNode,
4584                                        aBorderSecondNode,
4585                                        aBorderLastNode,
4586                                        aSide2FirstNode,
4587                                        aSide2SecondNode,
4588                                        aSide2ThirdNode,
4589                                        true,
4590                                        false, false) );
4591
4592   declareMeshModified( /*isReComputeSafe=*/false );
4593   return error;
4594
4595   SMESH_CATCH( SMESH::throwCorbaException );
4596   return SMESH::SMESH_MeshEditor::Sew_Error(0);
4597 }
4598
4599
4600 //=======================================================================
4601 //function : SewBorderToSide
4602 //purpose  :
4603 //=======================================================================
4604
4605 SMESH::SMESH_MeshEditor::Sew_Error
4606 SMESH_MeshEditor_i::SewBorderToSide(CORBA::Long FirstNodeIDOnFreeBorder,
4607                                     CORBA::Long SecondNodeIDOnFreeBorder,
4608                                     CORBA::Long LastNodeIDOnFreeBorder,
4609                                     CORBA::Long FirstNodeIDOnSide,
4610                                     CORBA::Long LastNodeIDOnSide,
4611                                     CORBA::Boolean CreatePolygons,
4612                                     CORBA::Boolean CreatePolyedrs)
4613   throw (SALOME::SALOME_Exception)
4614 {
4615   SMESH_TRY;
4616   initData();
4617
4618   SMESHDS_Mesh* aMesh = getMeshDS();
4619
4620   const SMDS_MeshNode* aBorderFirstNode  = aMesh->FindNode( FirstNodeIDOnFreeBorder  );
4621   const SMDS_MeshNode* aBorderSecondNode = aMesh->FindNode( SecondNodeIDOnFreeBorder );
4622   const SMDS_MeshNode* aBorderLastNode   = aMesh->FindNode( LastNodeIDOnFreeBorder   );
4623   const SMDS_MeshNode* aSide2FirstNode   = aMesh->FindNode( FirstNodeIDOnSide  );
4624   const SMDS_MeshNode* aSide2SecondNode  = aMesh->FindNode( LastNodeIDOnSide );
4625   const SMDS_MeshNode* aSide2ThirdNode   = 0;
4626
4627   if (!aBorderFirstNode ||
4628       !aBorderSecondNode||
4629       !aBorderLastNode  )
4630     return SMESH::SMESH_MeshEditor::SEW_BORDER1_NOT_FOUND;
4631   if (!aSide2FirstNode  ||
4632       !aSide2SecondNode)
4633     return SMESH::SMESH_MeshEditor::SEW_BAD_SIDE_NODES;
4634
4635   TPythonDump() << "error = " << this << ".SewBorderToSide( "
4636                 << FirstNodeIDOnFreeBorder  << ", "
4637                 << SecondNodeIDOnFreeBorder << ", "
4638                 << LastNodeIDOnFreeBorder   << ", "
4639                 << FirstNodeIDOnSide        << ", "
4640                 << LastNodeIDOnSide         << ", "
4641                 << CreatePolygons           << ", "
4642                 << CreatePolyedrs           << ") ";
4643
4644   SMESH::SMESH_MeshEditor::Sew_Error error =
4645     convError( getEditor().SewFreeBorder (aBorderFirstNode,
4646                                        aBorderSecondNode,
4647                                        aBorderLastNode,
4648                                        aSide2FirstNode,
4649                                        aSide2SecondNode,
4650                                        aSide2ThirdNode,
4651                                        false,
4652                                        CreatePolygons,
4653                                        CreatePolyedrs) );
4654
4655   declareMeshModified( /*isReComputeSafe=*/false );
4656   return error;
4657
4658   SMESH_CATCH( SMESH::throwCorbaException );
4659   return SMESH::SMESH_MeshEditor::Sew_Error(0);
4660 }
4661
4662
4663 //=======================================================================
4664 //function : SewSideElements
4665 //purpose  :
4666 //=======================================================================
4667
4668 SMESH::SMESH_MeshEditor::Sew_Error
4669 SMESH_MeshEditor_i::SewSideElements(const SMESH::long_array& IDsOfSide1Elements,
4670                                     const SMESH::long_array& IDsOfSide2Elements,
4671                                     CORBA::Long NodeID1OfSide1ToMerge,
4672                                     CORBA::Long NodeID1OfSide2ToMerge,
4673                                     CORBA::Long NodeID2OfSide1ToMerge,
4674                                     CORBA::Long NodeID2OfSide2ToMerge)
4675   throw (SALOME::SALOME_Exception)
4676 {
4677   SMESH_TRY;
4678   initData();
4679
4680   SMESHDS_Mesh* aMesh = getMeshDS();
4681
4682   const SMDS_MeshNode* aFirstNode1ToMerge  = aMesh->FindNode( NodeID1OfSide1ToMerge );
4683   const SMDS_MeshNode* aFirstNode2ToMerge  = aMesh->FindNode( NodeID1OfSide2ToMerge );
4684   const SMDS_MeshNode* aSecondNode1ToMerge = aMesh->FindNode( NodeID2OfSide1ToMerge );
4685   const SMDS_MeshNode* aSecondNode2ToMerge = aMesh->FindNode( NodeID2OfSide2ToMerge );
4686
4687   if (!aFirstNode1ToMerge ||
4688       !aFirstNode2ToMerge )
4689     return SMESH::SMESH_MeshEditor::SEW_BAD_SIDE1_NODES;
4690   if (!aSecondNode1ToMerge||
4691       !aSecondNode2ToMerge)
4692     return SMESH::SMESH_MeshEditor::SEW_BAD_SIDE2_NODES;
4693
4694   TIDSortedElemSet aSide1Elems, aSide2Elems;
4695   arrayToSet(IDsOfSide1Elements, aMesh, aSide1Elems);
4696   arrayToSet(IDsOfSide2Elements, aMesh, aSide2Elems);
4697
4698   TPythonDump() << "error = " << this << ".SewSideElements( "
4699                 << IDsOfSide1Elements << ", "
4700                 << IDsOfSide2Elements << ", "
4701                 << NodeID1OfSide1ToMerge << ", "
4702                 << NodeID1OfSide2ToMerge << ", "
4703                 << NodeID2OfSide1ToMerge << ", "
4704                 << NodeID2OfSide2ToMerge << ")";
4705
4706   SMESH::SMESH_MeshEditor::Sew_Error error =
4707     convError( getEditor().SewSideElements (aSide1Elems, aSide2Elems,
4708                                          aFirstNode1ToMerge,
4709                                          aFirstNode2ToMerge,
4710                                          aSecondNode1ToMerge,
4711                                          aSecondNode2ToMerge));
4712
4713   declareMeshModified( /*isReComputeSafe=*/false );
4714   return error;
4715
4716   SMESH_CATCH( SMESH::throwCorbaException );
4717   return SMESH::SMESH_MeshEditor::Sew_Error(0);
4718 }
4719
4720 //================================================================================
4721 /*!
4722  * \brief Set new nodes for given element
4723  * \param ide - element id
4724  * \param newIDs - new node ids
4725  * \retval CORBA::Boolean - true if result is OK
4726  */
4727 //================================================================================
4728
4729 CORBA::Boolean SMESH_MeshEditor_i::ChangeElemNodes(CORBA::Long ide,
4730                                                    const SMESH::long_array& newIDs)
4731   throw (SALOME::SALOME_Exception)
4732 {
4733   SMESH_TRY;
4734   initData();
4735
4736   const SMDS_MeshElement* elem = getMeshDS()->FindElement(ide);
4737   if(!elem) return false;
4738
4739   int nbn = newIDs.length();
4740   int i=0;
4741   vector<const SMDS_MeshNode*> aNodes(nbn);
4742   int nbn1=-1;
4743   for(; i<nbn; i++) {
4744     const SMDS_MeshNode* aNode = getMeshDS()->FindNode(newIDs[i]);
4745     if(aNode) {
4746       nbn1++;
4747       aNodes[nbn1] = aNode;
4748     }
4749   }
4750   TPythonDump() << "isDone = " << this << ".ChangeElemNodes( "
4751                 << ide << ", " << newIDs << " )";
4752
4753   MESSAGE("ChangeElementNodes");
4754   bool res = getMeshDS()->ChangeElementNodes( elem, & aNodes[0], nbn1+1 );
4755
4756   declareMeshModified( /*isReComputeSafe=*/ !res );
4757
4758   return res;
4759
4760   SMESH_CATCH( SMESH::throwCorbaException );
4761   return 0;
4762 }
4763
4764 //=======================================================================
4765 /*!
4766  * \brief Makes a part of the mesh quadratic or bi-quadratic
4767  */
4768 //=======================================================================
4769
4770 void SMESH_MeshEditor_i::convertToQuadratic(CORBA::Boolean            theForce3d,
4771                                             CORBA::Boolean            theToBiQuad,
4772                                             SMESH::SMESH_IDSource_ptr theObject)
4773   throw (SALOME::SALOME_Exception)
4774 {
4775   SMESH_TRY;
4776   TIDSortedElemSet elems;
4777   bool elemsOK;
4778   if ( !( elemsOK = CORBA::is_nil( theObject )))
4779   {
4780     elemsOK =  idSourceToSet( theObject, getMeshDS(), elems,
4781                               SMDSAbs_All, /*emptyIfIsMesh=*/true );
4782   }
4783   if ( elemsOK )
4784   {
4785     if ( !elems.empty() && (*elems.begin())->GetType() == SMDSAbs_Node )
4786       THROW_SALOME_CORBA_EXCEPTION("Group of nodes is not allowed", SALOME::BAD_PARAM);
4787
4788     if ( elems.empty() ) getEditor().ConvertToQuadratic(theForce3d, theToBiQuad);
4789     else                 getEditor().ConvertToQuadratic(theForce3d, elems, theToBiQuad);
4790
4791     declareMeshModified( /*isReComputeSafe=*/false );
4792   }
4793
4794   SMESH_CATCH( SMESH::throwCorbaException );
4795 }
4796
4797 //=======================================================================
4798 //function : ConvertFromQuadratic
4799 //purpose  :
4800 //=======================================================================
4801
4802 CORBA::Boolean SMESH_MeshEditor_i::ConvertFromQuadratic()
4803   throw (SALOME::SALOME_Exception)
4804 {
4805   CORBA::Boolean isDone = getEditor().ConvertFromQuadratic();
4806   TPythonDump() << this << ".ConvertFromQuadratic()";
4807   declareMeshModified( /*isReComputeSafe=*/!isDone );
4808   return isDone;
4809 }
4810
4811 //=======================================================================
4812 //function : ConvertToQuadratic
4813 //purpose  :
4814 //=======================================================================
4815
4816 void SMESH_MeshEditor_i::ConvertToQuadratic(CORBA::Boolean theForce3d)
4817   throw (SALOME::SALOME_Exception)
4818 {
4819   convertToQuadratic( theForce3d, false );
4820   TPythonDump() << this << ".ConvertToQuadratic("<<theForce3d<<")";
4821 }
4822
4823 //================================================================================
4824 /*!
4825  * \brief Makes a part of the mesh quadratic
4826  */
4827 //================================================================================
4828
4829 void SMESH_MeshEditor_i::ConvertToQuadraticObject(CORBA::Boolean            theForce3d,
4830                                                   SMESH::SMESH_IDSource_ptr theObject)
4831   throw (SALOME::SALOME_Exception)
4832 {
4833   convertToQuadratic( theForce3d, false, theObject );
4834   TPythonDump() << this << ".ConvertToQuadraticObject("<<theForce3d<<", "<<theObject<<")";
4835 }
4836
4837 //================================================================================
4838 /*!
4839  * \brief Makes a part of the mesh bi-quadratic
4840  */
4841 //================================================================================
4842
4843 void SMESH_MeshEditor_i::ConvertToBiQuadratic(CORBA::Boolean            theForce3d,
4844                                               SMESH::SMESH_IDSource_ptr theObject)
4845   throw (SALOME::SALOME_Exception)
4846 {
4847   convertToQuadratic( theForce3d, true, theObject );
4848   TPythonDump() << this << ".ConvertToBiQuadratic("<<theForce3d<<", "<<theObject<<")";
4849 }
4850
4851 //================================================================================
4852 /*!
4853  * \brief Makes a part of the mesh linear
4854  */
4855 //================================================================================
4856
4857 void SMESH_MeshEditor_i::ConvertFromQuadraticObject(SMESH::SMESH_IDSource_ptr theObject)
4858   throw (SALOME::SALOME_Exception)
4859 {
4860   SMESH_TRY;
4861
4862   TPythonDump pyDump;
4863
4864   TIDSortedElemSet elems;
4865   if ( idSourceToSet( theObject, getMeshDS(), elems, SMDSAbs_All, /*emptyIfIsMesh=*/true ))
4866   {
4867     if ( elems.empty() )
4868     {
4869       ConvertFromQuadratic();
4870     }
4871     else if ( (*elems.begin())->GetType() == SMDSAbs_Node )
4872     {
4873       THROW_SALOME_CORBA_EXCEPTION("Group of nodes is not allowed", SALOME::BAD_PARAM);
4874     }
4875     else
4876     {
4877       getEditor().ConvertFromQuadratic(elems);
4878     }
4879   }
4880   declareMeshModified( /*isReComputeSafe=*/false );
4881
4882   pyDump << this << ".ConvertFromQuadraticObject( "<<theObject<<" )";
4883
4884   SMESH_CATCH( SMESH::throwCorbaException );
4885 }
4886
4887 //=======================================================================
4888 //function : makeMesh
4889 //purpose  : create a named imported mesh
4890 //=======================================================================
4891
4892 SMESH::SMESH_Mesh_ptr SMESH_MeshEditor_i::makeMesh(const char* theMeshName)
4893 {
4894   SMESH_Gen_i*              gen = SMESH_Gen_i::GetSMESHGen();
4895   SMESH::SMESH_Mesh_var    mesh = gen->CreateEmptyMesh();
4896   SALOMEDS::Study_var     study = gen->GetCurrentStudy();
4897   SALOMEDS::SObject_wrap meshSO = gen->ObjectToSObject( study, mesh );
4898   gen->SetName( meshSO, theMeshName, "Mesh" );
4899   gen->SetPixMap( meshSO, "ICON_SMESH_TREE_MESH_IMPORTED");
4900
4901   return mesh._retn();
4902 }
4903
4904 //=======================================================================
4905 //function : dumpGroupsList
4906 //purpose  :
4907 //=======================================================================
4908
4909 void SMESH_MeshEditor_i::dumpGroupsList(TPythonDump &               theDumpPython,
4910                                         const SMESH::ListOfGroups * theGroupList)
4911 {
4912   bool isDumpGroupList = ( theGroupList && theGroupList->length() > 0 );
4913   if ( isDumpGroupList )
4914     theDumpPython << theGroupList << " = ";
4915 }
4916
4917 //================================================================================
4918 /*!
4919   \brief Generates the unique group name.
4920   \param thePrefix name prefix
4921   \return unique name
4922 */
4923 //================================================================================
4924
4925 string SMESH_MeshEditor_i::generateGroupName(const string& thePrefix)
4926 {
4927   SMESH::ListOfGroups_var groups = myMesh_i->GetGroups();
4928   set<string> groupNames;
4929
4930   // Get existing group names
4931   for (int i = 0, nbGroups = groups->length(); i < nbGroups; i++ ) {
4932     SMESH::SMESH_GroupBase_var aGroup = groups[i];
4933     if (CORBA::is_nil(aGroup))
4934       continue;
4935
4936     CORBA::String_var name = aGroup->GetName();
4937     groupNames.insert( name.in() );
4938   }
4939
4940   // Find new name
4941   string name = thePrefix;
4942   int index = 0;
4943
4944   while (!groupNames.insert(name).second)
4945     name = SMESH_Comment( thePrefix ) << "_" << index++;
4946
4947   return name;
4948 }
4949
4950 //================================================================================
4951 /*!
4952  * \brief Prepare SMESH_IDSource for work
4953  */
4954 //================================================================================
4955
4956 void SMESH_MeshEditor_i::prepareIdSource(SMESH::SMESH_IDSource_ptr theObject)
4957 {
4958   if ( SMESH::Filter_i* filter = SMESH::DownCast<SMESH::Filter_i*>( theObject ))
4959   {
4960     SMESH::SMESH_Mesh_var mesh = myMesh_i->_this();
4961     filter->SetMesh( mesh );
4962   }
4963 }
4964 //================================================================================
4965 /*!
4966  * \brief Retrieve elements of given type from SMESH_IDSource
4967  */
4968 //================================================================================
4969
4970 bool SMESH_MeshEditor_i::idSourceToSet(SMESH::SMESH_IDSource_ptr  theIDSource,
4971                                        const SMESHDS_Mesh*        theMeshDS,
4972                                        TIDSortedElemSet&          theElemSet,
4973                                        const SMDSAbs_ElementType  theType,
4974                                        const bool                 emptyIfIsMesh,
4975                                        IDSource_Error*            error)
4976
4977 {
4978   if ( error ) *error = IDSource_OK;
4979
4980   if ( CORBA::is_nil( theIDSource ) )
4981   {
4982     if ( error ) *error = IDSource_INVALID;
4983     return false;
4984   }
4985   if ( emptyIfIsMesh && SMESH::DownCast<SMESH_Mesh_i*>( theIDSource ))
4986   {
4987     if ( error && getMeshDS()->GetMeshInfo().NbElements( theType ) == 0 )
4988       *error = IDSource_EMPTY;
4989     return true;
4990   }
4991   prepareIdSource( theIDSource );
4992   SMESH::long_array_var anIDs = theIDSource->GetIDs();
4993   if ( anIDs->length() == 0 )
4994   {
4995     if ( error ) *error = IDSource_EMPTY;
4996     return false;
4997   }
4998   SMESH::array_of_ElementType_var types = theIDSource->GetTypes();
4999   if ( types->length() == 1 && types[0] == SMESH::NODE ) // group of nodes
5000   {
5001     if ( theType == SMDSAbs_All || theType == SMDSAbs_Node )
5002     {
5003       arrayToSet( anIDs, getMeshDS(), theElemSet, SMDSAbs_Node );
5004     }
5005     else
5006     {
5007       if ( error ) *error = IDSource_INVALID;
5008       return false;
5009     }
5010   }
5011   else
5012   {
5013     arrayToSet( anIDs, getMeshDS(), theElemSet, theType);
5014     if ( bool(anIDs->length()) != bool(theElemSet.size()))
5015     {
5016       if ( error ) *error = IDSource_INVALID;
5017       return false;
5018     }
5019   }
5020   return true;
5021 }
5022
5023 //================================================================================
5024 /*!
5025  * \brief Duplicates given elements, i.e. creates new elements based on the
5026  *        same nodes as the given ones.
5027  * \param theElements - container of elements to duplicate.
5028  * \param theGroupName - a name of group to contain the generated elements.
5029  *                    If a group with such a name already exists, the new elements
5030  *                    are added to the existng group, else a new group is created.
5031  *                    If \a theGroupName is empty, new elements are not added 
5032  *                    in any group.
5033  * \return a group where the new elements are added. NULL if theGroupName == "".
5034  * \sa DoubleNode()
5035  */
5036 //================================================================================
5037
5038 SMESH::SMESH_Group_ptr
5039 SMESH_MeshEditor_i::DoubleElements(SMESH::SMESH_IDSource_ptr theElements,
5040                                    const char*               theGroupName)
5041   throw (SALOME::SALOME_Exception)
5042 {
5043   SMESH::SMESH_Group_var newGroup;
5044
5045   SMESH_TRY;
5046   initData();
5047
5048   TPythonDump pyDump;
5049
5050   TIDSortedElemSet elems;
5051   if ( idSourceToSet( theElements, getMeshDS(), elems, SMDSAbs_All, /*emptyIfIsMesh=*/true))
5052   {
5053     getEditor().DoubleElements( elems );
5054
5055     if ( strlen( theGroupName ) && !getEditor().GetLastCreatedElems().IsEmpty() )
5056     {
5057       // group type
5058       SMESH::ElementType type =
5059         SMESH::ElementType( getEditor().GetLastCreatedElems().Value(1)->GetType() );
5060       // find existing group
5061       SMESH::ListOfGroups_var groups = myMesh_i->GetGroups();
5062       for ( size_t i = 0; i < groups->length(); ++i )
5063         if ( groups[i]->GetType() == type )
5064         {
5065           CORBA::String_var name = groups[i]->GetName();
5066           if ( strcmp( name, theGroupName ) == 0 ) {
5067             newGroup = SMESH::SMESH_Group::_narrow( groups[i] );
5068             break;
5069           }
5070         }
5071       // create a new group
5072       if ( newGroup->_is_nil() )
5073         newGroup = myMesh_i->CreateGroup( type, theGroupName );
5074       // fill newGroup
5075       if ( SMESH_Group_i* group_i = SMESH::DownCast< SMESH_Group_i* >( newGroup ))
5076       {
5077         SMESHDS_Group* groupDS = static_cast< SMESHDS_Group* >( group_i->GetGroupDS() );
5078         const SMESH_SequenceOfElemPtr& aSeq = getEditor().GetLastCreatedElems();
5079         for ( int i = 1; i <= aSeq.Length(); i++ )
5080           groupDS->SMDSGroup().Add( aSeq(i) );
5081       }
5082     }
5083   }
5084   // python dump
5085   if ( !newGroup->_is_nil() )
5086     pyDump << newGroup << " = ";
5087   pyDump << this << ".DoubleElements( "
5088          << theElements << ", " << "'" << theGroupName <<"')";
5089
5090   SMESH_CATCH( SMESH::throwCorbaException );
5091
5092   return newGroup._retn();
5093 }
5094
5095 //================================================================================
5096 /*!
5097   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5098   \param theNodes - identifiers of nodes to be doubled
5099   \param theModifiedElems - identifiers of elements to be updated by the new (doubled)
5100          nodes. If list of element identifiers is empty then nodes are doubled but
5101          they not assigned to elements
5102   \return TRUE if operation has been completed successfully, FALSE otherwise
5103   \sa DoubleNode(), DoubleNodeGroup(), DoubleNodeGroups()
5104 */
5105 //================================================================================
5106
5107 CORBA::Boolean SMESH_MeshEditor_i::DoubleNodes( const SMESH::long_array& theNodes,
5108                                                 const SMESH::long_array& theModifiedElems )
5109   throw (SALOME::SALOME_Exception)
5110 {
5111   SMESH_TRY;
5112   initData();
5113
5114   list< int > aListOfNodes;
5115   int i, n;
5116   for ( i = 0, n = theNodes.length(); i < n; i++ )
5117     aListOfNodes.push_back( theNodes[ i ] );
5118
5119   list< int > aListOfElems;
5120   for ( i = 0, n = theModifiedElems.length(); i < n; i++ )
5121     aListOfElems.push_back( theModifiedElems[ i ] );
5122
5123   bool aResult = getEditor().DoubleNodes( aListOfNodes, aListOfElems );
5124
5125   declareMeshModified( /*isReComputeSafe=*/ !aResult );
5126
5127   // Update Python script
5128   TPythonDump() << this << ".DoubleNodes( " << theNodes << ", "<< theModifiedElems << " )";
5129
5130   return aResult;
5131
5132   SMESH_CATCH( SMESH::throwCorbaException );
5133   return 0;
5134 }
5135
5136 //================================================================================
5137 /*!
5138   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5139   This method provided for convenience works as DoubleNodes() described above.
5140   \param theNodeId - identifier of node to be doubled.
5141   \param theModifiedElems - identifiers of elements to be updated.
5142   \return TRUE if operation has been completed successfully, FALSE otherwise
5143   \sa DoubleNodes(), DoubleNodeGroup(), DoubleNodeGroups()
5144 */
5145 //================================================================================
5146
5147 CORBA::Boolean SMESH_MeshEditor_i::DoubleNode( CORBA::Long              theNodeId,
5148                                                const SMESH::long_array& theModifiedElems )
5149   throw (SALOME::SALOME_Exception)
5150 {
5151   SMESH_TRY;
5152   SMESH::long_array_var aNodes = new SMESH::long_array;
5153   aNodes->length( 1 );
5154   aNodes[ 0 ] = theNodeId;
5155
5156   TPythonDump pyDump; // suppress dump by the next line
5157
5158   CORBA::Boolean done = DoubleNodes( aNodes, theModifiedElems );
5159
5160   pyDump << this << ".DoubleNode( " << theNodeId << ", " << theModifiedElems << " )";
5161
5162   return done;
5163
5164   SMESH_CATCH( SMESH::throwCorbaException );
5165   return 0;
5166 }
5167
5168 //================================================================================
5169 /*!
5170   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5171   This method provided for convenience works as DoubleNodes() described above.
5172   \param theNodes - group of nodes to be doubled.
5173   \param theModifiedElems - group of elements to be updated.
5174   \return TRUE if operation has been completed successfully, FALSE otherwise
5175   \sa DoubleNode(), DoubleNodes(), DoubleNodeGroups()
5176 */
5177 //================================================================================
5178
5179 CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeGroup(SMESH::SMESH_GroupBase_ptr theNodes,
5180                                                    SMESH::SMESH_GroupBase_ptr theModifiedElems )
5181   throw (SALOME::SALOME_Exception)
5182 {
5183   SMESH_TRY;
5184   if ( CORBA::is_nil( theNodes ) && theNodes->GetType() != SMESH::NODE )
5185     return false;
5186
5187   SMESH::long_array_var aNodes = theNodes->GetListOfID();
5188   SMESH::long_array_var aModifiedElems;
5189   if ( !CORBA::is_nil( theModifiedElems ) )
5190     aModifiedElems = theModifiedElems->GetListOfID();
5191   else
5192   {
5193     aModifiedElems = new SMESH::long_array;
5194     aModifiedElems->length( 0 );
5195   }
5196
5197   TPythonDump pyDump; // suppress dump by the next line
5198
5199   bool done = DoubleNodes( aNodes, aModifiedElems );
5200
5201   pyDump << this << ".DoubleNodeGroup( " << theNodes << ", " << theModifiedElems << " )";
5202
5203   return done;
5204
5205   SMESH_CATCH( SMESH::throwCorbaException );
5206   return 0;
5207 }
5208
5209 //================================================================================
5210 /*!
5211  * \brief Creates a hole in a mesh by doubling the nodes of some particular elements.
5212  * Works as DoubleNodeGroup(), but returns a new group with newly created nodes.
5213  * \param theNodes - group of nodes to be doubled.
5214  * \param theModifiedElems - group of elements to be updated.
5215  * \return a new group with newly created nodes
5216  * \sa DoubleNodeGroup()
5217  */
5218 //================================================================================
5219
5220 SMESH::SMESH_Group_ptr
5221 SMESH_MeshEditor_i::DoubleNodeGroupNew( SMESH::SMESH_GroupBase_ptr theNodes,
5222                                         SMESH::SMESH_GroupBase_ptr theModifiedElems )
5223   throw (SALOME::SALOME_Exception)
5224 {
5225   SMESH_TRY;
5226   SMESH::SMESH_Group_var aNewGroup;
5227
5228   if ( CORBA::is_nil( theNodes ) && theNodes->GetType() != SMESH::NODE )
5229     return aNewGroup._retn();
5230
5231   // Duplicate nodes
5232   SMESH::long_array_var aNodes = theNodes->GetListOfID();
5233   SMESH::long_array_var aModifiedElems;
5234   if ( !CORBA::is_nil( theModifiedElems ) )
5235     aModifiedElems = theModifiedElems->GetListOfID();
5236   else {
5237     aModifiedElems = new SMESH::long_array;
5238     aModifiedElems->length( 0 );
5239   }
5240
5241   TPythonDump pyDump; // suppress dump by the next line
5242
5243   bool aResult = DoubleNodes( aNodes, aModifiedElems );
5244   if ( aResult )
5245   {
5246     // Create group with newly created nodes
5247     SMESH::long_array_var anIds = GetLastCreatedNodes();
5248     if (anIds->length() > 0) {
5249       string anUnindexedName (theNodes->GetName());
5250       string aNewName = generateGroupName(anUnindexedName + "_double");
5251       aNewGroup = myMesh_i->CreateGroup(SMESH::NODE, aNewName.c_str());
5252       aNewGroup->Add(anIds);
5253       pyDump << aNewGroup << " = ";
5254     }
5255   }
5256
5257   pyDump << this << ".DoubleNodeGroupNew( " << theNodes << ", "
5258          << theModifiedElems << " )";
5259
5260   return aNewGroup._retn();
5261
5262   SMESH_CATCH( SMESH::throwCorbaException );
5263   return 0;
5264 }
5265
5266 //================================================================================
5267 /*!
5268   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5269   This method provided for convenience works as DoubleNodes() described above.
5270   \param theNodes - list of groups of nodes to be doubled
5271   \param theModifiedElems - list of groups of elements to be updated.
5272   \return TRUE if operation has been completed successfully, FALSE otherwise
5273   \sa DoubleNode(), DoubleNodeGroup(), DoubleNodes()
5274 */
5275 //================================================================================
5276
5277 CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeGroups(const SMESH::ListOfGroups& theNodes,
5278                                                     const SMESH::ListOfGroups& theModifiedElems )
5279   throw (SALOME::SALOME_Exception)
5280 {
5281   SMESH_TRY;
5282   initData();
5283
5284   std::list< int > aNodes;
5285   int i, n, j, m;
5286   for ( i = 0, n = theNodes.length(); i < n; i++ )
5287   {
5288     SMESH::SMESH_GroupBase_var aGrp = theNodes[ i ];
5289     if ( !CORBA::is_nil( aGrp ) && aGrp->GetType() == SMESH::NODE )
5290     {
5291       SMESH::long_array_var aCurr = aGrp->GetListOfID();
5292       for ( j = 0, m = aCurr->length(); j < m; j++ )
5293         aNodes.push_back( aCurr[ j ] );
5294     }
5295   }
5296
5297   std::list< int > anElems;
5298   for ( i = 0, n = theModifiedElems.length(); i < n; i++ )
5299   {
5300     SMESH::SMESH_GroupBase_var aGrp = theModifiedElems[ i ];
5301     if ( !CORBA::is_nil( aGrp ) && aGrp->GetType() != SMESH::NODE )
5302     {
5303       SMESH::long_array_var aCurr = aGrp->GetListOfID();
5304       for ( j = 0, m = aCurr->length(); j < m; j++ )
5305         anElems.push_back( aCurr[ j ] );
5306     }
5307   }
5308
5309   bool aResult = getEditor().DoubleNodes( aNodes, anElems );
5310
5311   declareMeshModified( /*isReComputeSafe=*/false );
5312
5313   TPythonDump() << this << ".DoubleNodeGroups( " << theNodes << ", " << theModifiedElems << " )";
5314
5315   return aResult;
5316
5317   SMESH_CATCH( SMESH::throwCorbaException );
5318   return 0;
5319 }
5320
5321 //================================================================================
5322 /*!
5323  * \brief Creates a hole in a mesh by doubling the nodes of some particular elements.
5324  * Works as DoubleNodeGroups(), but returns a new group with newly created nodes.
5325  * \param theNodes - group of nodes to be doubled.
5326  * \param theModifiedElems - group of elements to be updated.
5327  * \return a new group with newly created nodes
5328  * \sa DoubleNodeGroups()
5329  */
5330 //================================================================================
5331
5332 SMESH::SMESH_Group_ptr
5333 SMESH_MeshEditor_i::DoubleNodeGroupsNew( const SMESH::ListOfGroups& theNodes,
5334                                          const SMESH::ListOfGroups& theModifiedElems )
5335   throw (SALOME::SALOME_Exception)
5336 {
5337   SMESH::SMESH_Group_var aNewGroup;
5338
5339   TPythonDump pyDump; // suppress dump by the next line
5340
5341   bool aResult = DoubleNodeGroups( theNodes, theModifiedElems );
5342
5343   if ( aResult )
5344   {
5345     // Create group with newly created nodes
5346     SMESH::long_array_var anIds = GetLastCreatedNodes();
5347     if (anIds->length() > 0) {
5348       string anUnindexedName (theNodes[0]->GetName());
5349       string aNewName = generateGroupName(anUnindexedName + "_double");
5350       aNewGroup = myMesh_i->CreateGroup(SMESH::NODE, aNewName.c_str());
5351       aNewGroup->Add(anIds);
5352       pyDump << aNewGroup << " = ";
5353     }
5354   }
5355
5356   pyDump << this << ".DoubleNodeGroupsNew( " << theNodes << ", "
5357          << theModifiedElems << " )";
5358
5359   return aNewGroup._retn();
5360 }
5361
5362
5363 //================================================================================
5364 /*!
5365   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5366   \param theElems - the list of elements (edges or faces) to be replicated
5367   The nodes for duplication could be found from these elements
5368   \param theNodesNot - list of nodes to NOT replicate
5369   \param theAffectedElems - the list of elements (cells and edges) to which the
5370   replicated nodes should be associated to.
5371   \return TRUE if operation has been completed successfully, FALSE otherwise
5372   \sa DoubleNodeGroup(), DoubleNodeGroups()
5373 */
5374 //================================================================================
5375
5376 CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeElem( const SMESH::long_array& theElems,
5377                                                    const SMESH::long_array& theNodesNot,
5378                                                    const SMESH::long_array& theAffectedElems )
5379   throw (SALOME::SALOME_Exception)
5380 {
5381   SMESH_TRY;
5382   initData();
5383
5384   SMESHDS_Mesh* aMeshDS = getMeshDS();
5385   TIDSortedElemSet anElems, aNodes, anAffected;
5386   arrayToSet(theElems, aMeshDS, anElems, SMDSAbs_All);
5387   arrayToSet(theNodesNot, aMeshDS, aNodes, SMDSAbs_Node);
5388   arrayToSet(theAffectedElems, aMeshDS, anAffected, SMDSAbs_All);
5389
5390   bool aResult = getEditor().DoubleNodes( anElems, aNodes, anAffected );
5391
5392   // Update Python script
5393   TPythonDump() << this << ".DoubleNodeElem( " << theElems << ", "
5394                 << theNodesNot << ", " << theAffectedElems << " )";
5395
5396   declareMeshModified( /*isReComputeSafe=*/false );
5397   return aResult;
5398
5399   SMESH_CATCH( SMESH::throwCorbaException );
5400   return 0;
5401 }
5402
5403 //================================================================================
5404 /*!
5405   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5406   \param theElems - the list of elements (edges or faces) to be replicated
5407   The nodes for duplication could be found from these elements
5408   \param theNodesNot - list of nodes to NOT replicate
5409   \param theShape - shape to detect affected elements (element which geometric center
5410   located on or inside shape).
5411   The replicated nodes should be associated to affected elements.
5412   \return TRUE if operation has been completed successfully, FALSE otherwise
5413   \sa DoubleNodeGroupInRegion(), DoubleNodeGroupsInRegion()
5414 */
5415 //================================================================================
5416
5417 CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeElemInRegion ( const SMESH::long_array& theElems,
5418                                                             const SMESH::long_array& theNodesNot,
5419                                                             GEOM::GEOM_Object_ptr    theShape )
5420   throw (SALOME::SALOME_Exception)
5421 {
5422   SMESH_TRY;
5423   initData();
5424
5425
5426   SMESHDS_Mesh* aMeshDS = getMeshDS();
5427   TIDSortedElemSet anElems, aNodes;
5428   arrayToSet(theElems, aMeshDS, anElems, SMDSAbs_All);
5429   arrayToSet(theNodesNot, aMeshDS, aNodes, SMDSAbs_Node);
5430
5431   TopoDS_Shape aShape = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape( theShape );
5432   bool aResult = getEditor().DoubleNodesInRegion( anElems, aNodes, aShape );
5433
5434   // Update Python script
5435   TPythonDump() << "isDone = " << this << ".DoubleNodeElemInRegion( " << theElems << ", "
5436                 << theNodesNot << ", " << theShape << " )";
5437
5438   declareMeshModified( /*isReComputeSafe=*/false );
5439   return aResult;
5440
5441   SMESH_CATCH( SMESH::throwCorbaException );
5442   return 0;
5443 }
5444
5445 //================================================================================
5446 /*!
5447   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5448   \param theElems - group of of elements (edges or faces) to be replicated
5449   \param theNodesNot - group of nodes not to replicated
5450   \param theAffectedElems - group of elements to which the replicated nodes
5451   should be associated to.
5452   \return TRUE if operation has been completed successfully, FALSE otherwise
5453   \sa DoubleNodes(), DoubleNodeGroups()
5454 */
5455 //================================================================================
5456
5457 CORBA::Boolean
5458 SMESH_MeshEditor_i::DoubleNodeElemGroup(SMESH::SMESH_GroupBase_ptr theElems,
5459                                         SMESH::SMESH_GroupBase_ptr theNodesNot,
5460                                         SMESH::SMESH_GroupBase_ptr theAffectedElems)
5461   throw (SALOME::SALOME_Exception)
5462 {
5463   SMESH_TRY;
5464   if ( CORBA::is_nil( theElems ) && theElems->GetType() == SMESH::NODE )
5465     return false;
5466
5467   initData();
5468
5469
5470   SMESHDS_Mesh* aMeshDS = getMeshDS();
5471   TIDSortedElemSet anElems, aNodes, anAffected;
5472   idSourceToSet( theElems, aMeshDS, anElems, SMDSAbs_All );
5473   idSourceToSet( theNodesNot, aMeshDS, aNodes, SMDSAbs_Node );
5474   idSourceToSet( theAffectedElems, aMeshDS, anAffected, SMDSAbs_All );
5475
5476   bool aResult = getEditor().DoubleNodes( anElems, aNodes, anAffected );
5477
5478   // Update Python script
5479   TPythonDump() << "isDone = " << this << ".DoubleNodeElemGroup( " << theElems << ", "
5480                 << theNodesNot << ", " << theAffectedElems << " )";
5481
5482   declareMeshModified( /*isReComputeSafe=*/false );
5483   return aResult;
5484
5485   SMESH_CATCH( SMESH::throwCorbaException );
5486   return 0;
5487 }
5488
5489 //================================================================================
5490 /*!
5491  * \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5492  * Works as DoubleNodeElemGroup(), but returns a new group with newly created elements.
5493  * \param theElems - group of of elements (edges or faces) to be replicated
5494  * \param theNodesNot - group of nodes not to replicated
5495  * \param theAffectedElems - group of elements to which the replicated nodes
5496  *        should be associated to.
5497  * \return a new group with newly created elements
5498  * \sa DoubleNodeElemGroup()
5499  */
5500 //================================================================================
5501
5502 SMESH::SMESH_Group_ptr
5503 SMESH_MeshEditor_i::DoubleNodeElemGroupNew(SMESH::SMESH_GroupBase_ptr theElems,
5504                                            SMESH::SMESH_GroupBase_ptr theNodesNot,
5505                                            SMESH::SMESH_GroupBase_ptr theAffectedElems)
5506   throw (SALOME::SALOME_Exception)
5507 {
5508   TPythonDump pyDump;
5509   SMESH::ListOfGroups_var twoGroups = DoubleNodeElemGroup2New( theElems,
5510                                                                theNodesNot,
5511                                                                theAffectedElems,
5512                                                                true, false );
5513   SMESH::SMESH_GroupBase_var baseGroup = twoGroups[0].in();
5514   SMESH::SMESH_Group_var     elemGroup = SMESH::SMESH_Group::_narrow( baseGroup );
5515
5516   pyDump << elemGroup << " = " << this << ".DoubleNodeElemGroupNew( "
5517          << theElems         << ", "
5518          << theNodesNot      << ", "
5519          << theAffectedElems << " )";
5520
5521   return elemGroup._retn();
5522 }
5523
5524 //================================================================================
5525 /*!
5526  * \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5527  * Works as DoubleNodeElemGroup(), but returns a new group with newly created elements.
5528  * \param theElems - group of of elements (edges or faces) to be replicated
5529  * \param theNodesNot - group of nodes not to replicated
5530  * \param theAffectedElems - group of elements to which the replicated nodes
5531  *        should be associated to.
5532  * \return a new group with newly created elements
5533  * \sa DoubleNodeElemGroup()
5534  */
5535 //================================================================================
5536
5537 SMESH::ListOfGroups*
5538 SMESH_MeshEditor_i::DoubleNodeElemGroup2New(SMESH::SMESH_GroupBase_ptr theElems,
5539                                             SMESH::SMESH_GroupBase_ptr theNodesNot,
5540                                             SMESH::SMESH_GroupBase_ptr theAffectedElems,
5541                                             CORBA::Boolean             theElemGroupNeeded,
5542                                             CORBA::Boolean             theNodeGroupNeeded)
5543   throw (SALOME::SALOME_Exception)
5544 {
5545   SMESH_TRY;
5546   SMESH::SMESH_Group_var aNewElemGroup, aNewNodeGroup;
5547   SMESH::ListOfGroups_var aTwoGroups = new SMESH::ListOfGroups();
5548   aTwoGroups->length( 2 );
5549
5550   if ( CORBA::is_nil( theElems ) && theElems->GetType() == SMESH::NODE )
5551     return aTwoGroups._retn();
5552
5553   initData();
5554
5555
5556   SMESHDS_Mesh* aMeshDS = getMeshDS();
5557   TIDSortedElemSet anElems, aNodes, anAffected;
5558   idSourceToSet( theElems, aMeshDS, anElems, SMDSAbs_All );
5559   idSourceToSet( theNodesNot, aMeshDS, aNodes, SMDSAbs_Node );
5560   idSourceToSet( theAffectedElems, aMeshDS, anAffected, SMDSAbs_All );
5561
5562
5563   bool aResult = getEditor().DoubleNodes( anElems, aNodes, anAffected );
5564
5565   declareMeshModified( /*isReComputeSafe=*/ !aResult );
5566
5567   TPythonDump pyDump;
5568
5569   if ( aResult )
5570   {
5571     // Create group with newly created elements
5572     CORBA::String_var elemGroupName = theElems->GetName();
5573     string aNewName = generateGroupName( string(elemGroupName.in()) + "_double");
5574     if ( !getEditor().GetLastCreatedElems().IsEmpty() && theElemGroupNeeded )
5575     {
5576       SMESH::long_array_var anIds = GetLastCreatedElems();
5577       SMESH::ElementType aGroupType = myMesh_i->GetElementType(anIds[0], true);
5578       aNewElemGroup = myMesh_i->CreateGroup(aGroupType, aNewName.c_str());
5579       aNewElemGroup->Add(anIds);
5580     }
5581     if ( !getEditor().GetLastCreatedNodes().IsEmpty() && theNodeGroupNeeded )
5582     {
5583       SMESH::long_array_var anIds = GetLastCreatedNodes();
5584       aNewNodeGroup = myMesh_i->CreateGroup(SMESH::NODE, aNewName.c_str());
5585       aNewNodeGroup->Add(anIds);
5586     }
5587   }
5588
5589   // Update Python script
5590
5591   pyDump << "[ ";
5592   if ( aNewElemGroup->_is_nil() ) pyDump << "nothing, ";
5593   else                            pyDump << aNewElemGroup << ", ";
5594   if ( aNewNodeGroup->_is_nil() ) pyDump << "nothing ] = ";
5595   else                            pyDump << aNewNodeGroup << " ] = ";
5596
5597   pyDump << this << ".DoubleNodeElemGroup2New( " << theElems << ", "
5598          << theNodesNot        << ", "
5599          << theAffectedElems   << ", "
5600          << theElemGroupNeeded << ", "
5601          << theNodeGroupNeeded <<" )";
5602
5603   aTwoGroups[0] = aNewElemGroup._retn();
5604   aTwoGroups[1] = aNewNodeGroup._retn();
5605   return aTwoGroups._retn();
5606
5607   SMESH_CATCH( SMESH::throwCorbaException );
5608   return 0;
5609 }
5610
5611 //================================================================================
5612 /*!
5613   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5614   \param theElems - group of of elements (edges or faces) to be replicated
5615   \param theNodesNot - group of nodes not to replicated
5616   \param theShape - shape to detect affected elements (element which geometric center
5617   located on or inside shape).
5618   The replicated nodes should be associated to affected elements.
5619   \return TRUE if operation has been completed successfully, FALSE otherwise
5620   \sa DoubleNodesInRegion(), DoubleNodeGroupsInRegion()
5621 */
5622 //================================================================================
5623
5624 CORBA::Boolean
5625 SMESH_MeshEditor_i::DoubleNodeElemGroupInRegion(SMESH::SMESH_GroupBase_ptr theElems,
5626                                                 SMESH::SMESH_GroupBase_ptr theNodesNot,
5627                                                 GEOM::GEOM_Object_ptr      theShape )
5628   throw (SALOME::SALOME_Exception)
5629 {
5630   SMESH_TRY;
5631   if ( CORBA::is_nil( theElems ) && theElems->GetType() == SMESH::NODE )
5632     return false;
5633
5634   initData();
5635
5636
5637   SMESHDS_Mesh* aMeshDS = getMeshDS();
5638   TIDSortedElemSet anElems, aNodes, anAffected;
5639   idSourceToSet( theElems, aMeshDS, anElems, SMDSAbs_All );
5640   idSourceToSet( theNodesNot, aMeshDS, aNodes, SMDSAbs_Node );
5641
5642   TopoDS_Shape aShape = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape( theShape );
5643   bool aResult = getEditor().DoubleNodesInRegion( anElems, aNodes, aShape );
5644
5645
5646   declareMeshModified( /*isReComputeSafe=*/ !aResult );
5647
5648   // Update Python script
5649   TPythonDump() << "isDone = " << this << ".DoubleNodeElemGroupInRegion( " << theElems << ", "
5650                 << theNodesNot << ", " << theShape << " )";
5651   return aResult;
5652
5653   SMESH_CATCH( SMESH::throwCorbaException );
5654   return 0;
5655 }
5656
5657 //================================================================================
5658 /*!
5659  * \brief Re-load elements from a list of groups into a TIDSortedElemSet
5660  *  \param [in] theGrpList - groups
5661  *  \param [in] theMeshDS -  mesh
5662  *  \param [out] theElemSet - set of elements
5663  *  \param [in] theIsNodeGrp - is \a theGrpList includes goups of nodes
5664  */
5665 //================================================================================
5666
5667 static void listOfGroupToSet(const SMESH::ListOfGroups& theGrpList,
5668                              SMESHDS_Mesh*              theMeshDS,
5669                              TIDSortedElemSet&          theElemSet,
5670                              const bool                 theIsNodeGrp)
5671 {
5672   for ( int i = 0, n = theGrpList.length(); i < n; i++ )
5673   {
5674     SMESH::SMESH_GroupBase_var aGrp = theGrpList[ i ];
5675     if ( !CORBA::is_nil( aGrp ) && (theIsNodeGrp ? aGrp->GetType() == SMESH::NODE
5676                                     : aGrp->GetType() != SMESH::NODE ) )
5677     {
5678       SMESH::long_array_var anIDs = aGrp->GetIDs();
5679       arrayToSet( anIDs, theMeshDS, theElemSet, theIsNodeGrp ? SMDSAbs_Node : SMDSAbs_All );
5680     }
5681   }
5682 }
5683
5684 //================================================================================
5685 /*!
5686   \brief Creates a hole in a mesh by doubling the nodes of some particular elements.
5687   This method provided for convenience works as DoubleNodes() described above.
5688   \param theElems - list of groups of elements (edges or faces) to be replicated
5689   \param theNodesNot - list of groups of nodes not to replicated
5690   \param theAffectedElems - group of elements to which the replicated nodes
5691   should be associated to.
5692   \return TRUE if operation has been completed successfully, FALSE otherwise
5693   \sa DoubleNodeGroup(), DoubleNodes(), DoubleNodeElemGroupsNew()
5694 */
5695 //================================================================================
5696
5697 CORBA::Boolean
5698 SMESH_MeshEditor_i::DoubleNodeElemGroups(const SMESH::ListOfGroups& theElems,
5699                                          const SMESH::ListOfGroups& theNodesNot,
5700                                          const SMESH::ListOfGroups& theAffectedElems)
5701   throw (SALOME::SALOME_Exception)
5702 {
5703   SMESH_TRY;
5704   initData();
5705
5706
5707   SMESHDS_Mesh* aMeshDS = getMeshDS();
5708   TIDSortedElemSet anElems, aNodes, anAffected;
5709   listOfGroupToSet(theElems, aMeshDS, anElems, false );
5710   listOfGroupToSet(theNodesNot, aMeshDS, aNodes, true );
5711   listOfGroupToSet(theAffectedElems, aMeshDS, anAffected, false );
5712
5713   bool aResult = getEditor().DoubleNodes( anElems, aNodes, anAffected );
5714
5715   // Update Python script
5716   TPythonDump() << "isDone = " << this << ".DoubleNodeElemGroups( " << &theElems << ", "
5717                 << &theNodesNot << ", " << &theAffectedElems << " )";
5718
5719   declareMeshModified( /*isReComputeSafe=*/false );
5720   return aResult;
5721
5722   SMESH_CATCH( SMESH::throwCorbaException );
5723   return 0;
5724 }
5725
5726 //================================================================================
5727 /*!
5728  * \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5729  * Works as DoubleNodeElemGroups(), but returns a new group with newly created elements.
5730   \param theElems - list of groups of elements (edges or faces) to be replicated
5731   \param theNodesNot - list of groups of nodes not to replicated
5732   \param theAffectedElems - group of elements to which the replicated nodes
5733   should be associated to.
5734  * \return a new group with newly created elements
5735  * \sa DoubleNodeElemGroups()
5736  */
5737 //================================================================================
5738
5739 SMESH::SMESH_Group_ptr
5740 SMESH_MeshEditor_i::DoubleNodeElemGroupsNew(const SMESH::ListOfGroups& theElems,
5741                                             const SMESH::ListOfGroups& theNodesNot,
5742                                             const SMESH::ListOfGroups& theAffectedElems)
5743   throw (SALOME::SALOME_Exception)
5744 {
5745   TPythonDump pyDump;
5746   SMESH::ListOfGroups_var twoGroups = DoubleNodeElemGroups2New( theElems,
5747                                                                 theNodesNot,
5748                                                                 theAffectedElems,
5749                                                                 true, false );
5750   SMESH::SMESH_GroupBase_var baseGroup = twoGroups[0].in();
5751   SMESH::SMESH_Group_var     elemGroup = SMESH::SMESH_Group::_narrow( baseGroup );
5752
5753   pyDump << elemGroup << " = " << this << ".DoubleNodeElemGroupsNew( "
5754          << theElems         << ", "
5755          << theNodesNot      << ", "
5756          << theAffectedElems << " )";
5757
5758   return elemGroup._retn();
5759 }
5760
5761 //================================================================================
5762 /*!
5763  * \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5764  * Works as DoubleNodeElemGroups(), but returns a new group with newly created elements.
5765   \param theElems - list of groups of elements (edges or faces) to be replicated
5766   \param theNodesNot - list of groups of nodes not to replicated
5767   \param theAffectedElems - group of elements to which the replicated nodes
5768   should be associated to.
5769  * \return a new group with newly created elements
5770  * \sa DoubleNodeElemGroups()
5771  */
5772 //================================================================================
5773
5774 SMESH::ListOfGroups*
5775 SMESH_MeshEditor_i::DoubleNodeElemGroups2New(const SMESH::ListOfGroups& theElems,
5776                                              const SMESH::ListOfGroups& theNodesNot,
5777                                              const SMESH::ListOfGroups& theAffectedElems,
5778                                              CORBA::Boolean             theElemGroupNeeded,
5779                                              CORBA::Boolean             theNodeGroupNeeded)
5780   throw (SALOME::SALOME_Exception)
5781 {
5782   SMESH_TRY;
5783   SMESH::SMESH_Group_var aNewElemGroup, aNewNodeGroup;
5784   SMESH::ListOfGroups_var aTwoGroups = new SMESH::ListOfGroups();
5785   aTwoGroups->length( 2 );
5786   
5787   initData();
5788
5789
5790   SMESHDS_Mesh* aMeshDS = getMeshDS();
5791   TIDSortedElemSet anElems, aNodes, anAffected;
5792   listOfGroupToSet(theElems, aMeshDS, anElems, false );
5793   listOfGroupToSet(theNodesNot, aMeshDS, aNodes, true );
5794   listOfGroupToSet(theAffectedElems, aMeshDS, anAffected, false );
5795
5796   bool aResult = getEditor().DoubleNodes( anElems, aNodes, anAffected );
5797
5798   declareMeshModified( /*isReComputeSafe=*/ !aResult );
5799
5800   TPythonDump pyDump;
5801   if ( aResult )
5802   {
5803     // Create group with newly created elements
5804     CORBA::String_var elemGroupName = theElems[0]->GetName();
5805     string aNewName = generateGroupName( string(elemGroupName.in()) + "_double");
5806     if ( !getEditor().GetLastCreatedElems().IsEmpty() && theElemGroupNeeded )
5807     {
5808       SMESH::long_array_var anIds = GetLastCreatedElems();
5809       SMESH::ElementType aGroupType = myMesh_i->GetElementType(anIds[0], true);
5810       aNewElemGroup = myMesh_i->CreateGroup(aGroupType, aNewName.c_str());
5811       aNewElemGroup->Add(anIds);
5812     }
5813     if ( !getEditor().GetLastCreatedNodes().IsEmpty() && theNodeGroupNeeded )
5814     {
5815       SMESH::long_array_var anIds = GetLastCreatedNodes();
5816       aNewNodeGroup = myMesh_i->CreateGroup(SMESH::NODE, aNewName.c_str());
5817       aNewNodeGroup->Add(anIds);
5818     }
5819   }
5820
5821   // Update Python script
5822
5823   pyDump << "[ ";
5824   if ( aNewElemGroup->_is_nil() ) pyDump << "nothing, ";
5825   else                            pyDump << aNewElemGroup << ", ";
5826   if ( aNewNodeGroup->_is_nil() ) pyDump << "nothing ] = ";
5827   else                            pyDump << aNewNodeGroup << " ] = ";
5828
5829   pyDump << this << ".DoubleNodeElemGroups2New( " << &theElems << ", "
5830          << &theNodesNot       << ", "
5831          << &theAffectedElems  << ", "
5832          << theElemGroupNeeded << ", "
5833          << theNodeGroupNeeded << " )";
5834
5835   aTwoGroups[0] = aNewElemGroup._retn();
5836   aTwoGroups[1] = aNewNodeGroup._retn();
5837   return aTwoGroups._retn();
5838
5839   SMESH_CATCH( SMESH::throwCorbaException );
5840   return 0;
5841 }
5842
5843 //================================================================================
5844 /*!
5845   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5846   This method provided for convenience works as DoubleNodes() described above.
5847   \param theElems - list of groups of elements (edges or faces) to be replicated
5848   \param theNodesNot - list of groups of nodes not to replicated
5849   \param theShape - shape to detect affected elements (element which geometric center
5850   located on or inside shape).
5851   The replicated nodes should be associated to affected elements.
5852   \return TRUE if operation has been completed successfully, FALSE otherwise
5853   \sa DoubleNodeGroupInRegion(), DoubleNodesInRegion()
5854 */
5855 //================================================================================
5856
5857 CORBA::Boolean
5858 SMESH_MeshEditor_i::DoubleNodeElemGroupsInRegion(const SMESH::ListOfGroups& theElems,
5859                                                  const SMESH::ListOfGroups& theNodesNot,
5860                                                  GEOM::GEOM_Object_ptr      theShape )
5861   throw (SALOME::SALOME_Exception)
5862 {
5863   SMESH_TRY;
5864   initData();
5865
5866
5867   SMESHDS_Mesh* aMeshDS = getMeshDS();
5868   TIDSortedElemSet anElems, aNodes;
5869   listOfGroupToSet(theElems, aMeshDS, anElems,false );
5870   listOfGroupToSet(theNodesNot, aMeshDS, aNodes, true );
5871
5872   TopoDS_Shape aShape = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape( theShape );
5873   bool aResult = getEditor().DoubleNodesInRegion( anElems, aNodes, aShape );
5874
5875   // Update Python script
5876   TPythonDump() << "isDone = " << this << ".DoubleNodeElemGroupsInRegion( " << &theElems << ", "
5877                 << &theNodesNot << ", " << theShape << " )";
5878
5879   declareMeshModified( /*isReComputeSafe=*/ !aResult );
5880   return aResult;
5881
5882   SMESH_CATCH( SMESH::throwCorbaException );
5883   return 0;
5884 }
5885
5886 //================================================================================
5887 /*!
5888   \brief Identify the elements that will be affected by node duplication (actual
5889          duplication is not performed.
5890   This method is the first step of DoubleNodeElemGroupsInRegion.
5891   \param theElems - list of groups of elements (edges or faces) to be replicated
5892   \param theNodesNot - list of groups of nodes not to replicated
5893   \param theShape - shape to detect affected elements (element which geometric center
5894          located on or inside shape).
5895          The replicated nodes should be associated to affected elements.
5896   \return groups of affected elements
5897   \sa DoubleNodeElemGroupsInRegion()
5898 */
5899 //================================================================================
5900 SMESH::ListOfGroups*
5901 SMESH_MeshEditor_i::AffectedElemGroupsInRegion( const SMESH::ListOfGroups& theElems,
5902                                                 const SMESH::ListOfGroups& theNodesNot,
5903                                                 GEOM::GEOM_Object_ptr      theShape )
5904   throw (SALOME::SALOME_Exception)
5905 {
5906   SMESH_TRY;
5907   MESSAGE("AffectedElemGroupsInRegion");
5908   SMESH::ListOfGroups_var aListOfGroups = new SMESH::ListOfGroups();
5909   bool isEdgeGroup = false;
5910   bool isFaceGroup = false;
5911   bool isVolumeGroup = false;
5912   SMESH::SMESH_Group_var aNewEdgeGroup = myMesh_i->CreateGroup(SMESH::EDGE, "affectedEdges");
5913   SMESH::SMESH_Group_var aNewFaceGroup = myMesh_i->CreateGroup(SMESH::FACE, "affectedFaces");
5914   SMESH::SMESH_Group_var aNewVolumeGroup = myMesh_i->CreateGroup(SMESH::VOLUME, "affectedVolumes");
5915
5916   initData();
5917
5918   ::SMESH_MeshEditor aMeshEditor(myMesh);
5919
5920   SMESHDS_Mesh* aMeshDS = getMeshDS();
5921   TIDSortedElemSet anElems, aNodes;
5922   listOfGroupToSet(theElems, aMeshDS, anElems, false);
5923   listOfGroupToSet(theNodesNot, aMeshDS, aNodes, true);
5924
5925   TopoDS_Shape aShape = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape(theShape);
5926   TIDSortedElemSet anAffected;
5927   bool aResult = aMeshEditor.AffectedElemGroupsInRegion(anElems, aNodes, aShape, anAffected);
5928
5929
5930   declareMeshModified( /*isReComputeSafe=*/ !aResult );
5931
5932   TPythonDump pyDump;
5933   if (aResult)
5934   {
5935     int lg = anAffected.size();
5936     MESSAGE("lg="<< lg);
5937     SMESH::long_array_var volumeIds = new SMESH::long_array;
5938     volumeIds->length(lg);
5939     SMESH::long_array_var faceIds = new SMESH::long_array;
5940     faceIds->length(lg);
5941     SMESH::long_array_var edgeIds = new SMESH::long_array;
5942     edgeIds->length(lg);
5943     int ivol = 0;
5944     int iface = 0;
5945     int iedge = 0;
5946
5947     TIDSortedElemSet::const_iterator eIt = anAffected.begin();
5948     for (; eIt != anAffected.end(); ++eIt)
5949     {
5950       const SMDS_MeshElement* anElem = *eIt;
5951       if (!anElem)
5952         continue;
5953       int elemId = anElem->GetID();
5954       if (myMesh->GetElementType(elemId, true) == SMDSAbs_Volume)
5955         volumeIds[ivol++] = elemId;
5956       else if (myMesh->GetElementType(elemId, true) == SMDSAbs_Face)
5957         faceIds[iface++] = elemId;
5958       else if (myMesh->GetElementType(elemId, true) == SMDSAbs_Edge)
5959         edgeIds[iedge++] = elemId;
5960     }
5961     volumeIds->length(ivol);
5962     faceIds->length(iface);
5963     edgeIds->length(iedge);
5964
5965     aNewVolumeGroup->Add(volumeIds);
5966     aNewFaceGroup->Add(faceIds);
5967     aNewEdgeGroup->Add(edgeIds);
5968     isVolumeGroup = (aNewVolumeGroup->Size() > 0);
5969     isFaceGroup = (aNewFaceGroup->Size() > 0);
5970     isEdgeGroup = (aNewEdgeGroup->Size() > 0);
5971   }
5972
5973   int nbGroups = 0;
5974   if (isEdgeGroup)   nbGroups++;
5975   if (isFaceGroup)   nbGroups++;
5976   if (isVolumeGroup) nbGroups++;
5977   aListOfGroups->length(nbGroups);
5978
5979   int i = 0;
5980   if (isEdgeGroup)   aListOfGroups[i++] = aNewEdgeGroup._retn();
5981   if (isFaceGroup)   aListOfGroups[i++] = aNewFaceGroup._retn();
5982   if (isVolumeGroup) aListOfGroups[i++] = aNewVolumeGroup._retn();
5983
5984   // Update Python script
5985
5986   pyDump << "[ ";
5987   if (isEdgeGroup)   pyDump << aNewEdgeGroup << ", ";
5988   if (isFaceGroup)   pyDump << aNewFaceGroup << ", ";
5989   if (isVolumeGroup) pyDump << aNewVolumeGroup << ", ";
5990   pyDump << "] = ";
5991   pyDump << this << ".AffectedElemGroupsInRegion( "
5992          << &theElems << ", " << &theNodesNot << ", " << theShape << " )";
5993
5994   return aListOfGroups._retn();
5995
5996   SMESH_CATCH( SMESH::throwCorbaException );
5997   return 0;
5998 }
5999
6000 //================================================================================
6001 /*!
6002   \brief Generated skin mesh (containing 2D cells) from 3D mesh
6003    The created 2D mesh elements based on nodes of free faces of boundary volumes
6004   \return TRUE if operation has been completed successfully, FALSE otherwise
6005 */
6006 //================================================================================
6007
6008 CORBA::Boolean SMESH_MeshEditor_i::Make2DMeshFrom3D()
6009   throw (SALOME::SALOME_Exception)
6010 {
6011   SMESH_TRY;
6012   initData();
6013
6014   bool aResult = getEditor().Make2DMeshFrom3D();
6015
6016   TPythonDump() << "isDone = " << this << ".Make2DMeshFrom3D()";
6017
6018   declareMeshModified( /*isReComputeSafe=*/ !aResult );
6019   return aResult;
6020
6021   SMESH_CATCH( SMESH::throwCorbaException );
6022   return false;
6023 }
6024
6025 //================================================================================
6026 /*!
6027  * \brief Double nodes on shared faces between groups of volumes and create flat elements on demand.
6028  * The list of groups must contain at least two groups. The groups have to be disjoint:
6029  * no common element into two different groups.
6030  * The nodes of the internal faces at the boundaries of the groups are doubled.
6031  * Optionally, the internal faces are replaced by flat elements.
6032  * Triangles are transformed into prisms, and quadrangles into hexahedrons.
6033  * The flat elements are stored in groups of volumes.
6034  * These groups are named according to the position of the group in the list:
6035  * the group j_n_p is the group of the flat elements that are built between the group #n and the group #p in the list.
6036  * If there is no shared faces between the group #n and the group #p in the list, the group j_n_p is not created.
6037  * All the flat elements are gathered into the group named "joints3D" (or "joints2D" in 2D situation).
6038  * The flat element of the multiple junctions between the simple junction are stored in a group named "jointsMultiples".
6039  * \param theDomains - list of groups of volumes
6040  * \param createJointElems - if TRUE, create the elements
6041  * \param onAllBoundaries - if TRUE, the nodes and elements are also created on
6042  *        the boundary between \a theDomains and the rest mesh
6043  * \return TRUE if operation has been completed successfully, FALSE otherwise
6044  */
6045 //================================================================================
6046
6047 CORBA::Boolean
6048 SMESH_MeshEditor_i::DoubleNodesOnGroupBoundaries( const SMESH::ListOfGroups& theDomains,
6049                                                   CORBA::Boolean             createJointElems,
6050                                                   CORBA::Boolean             onAllBoundaries )
6051   throw (SALOME::SALOME_Exception)
6052 {
6053   bool isOK = false;
6054
6055   SMESH_TRY;
6056   initData();
6057
6058   SMESHDS_Mesh* aMeshDS = getMeshDS();
6059
6060   // MESSAGE("theDomains.length = "<<theDomains.length());
6061   if ( theDomains.length() <= 1 && !onAllBoundaries )
6062     THROW_SALOME_CORBA_EXCEPTION("At least 2 groups are required.", SALOME::BAD_PARAM);
6063
6064   vector<TIDSortedElemSet> domains;
6065   domains.resize( theDomains.length() );
6066
6067   for ( int i = 0, n = theDomains.length(); i < n; i++ )
6068   {
6069     SMESH::SMESH_GroupBase_var aGrp = theDomains[ i ];
6070     if ( !CORBA::is_nil( aGrp ) /*&& ( aGrp->GetType() != SMESH::NODE )*/ )
6071     {
6072 //      if ( aGrp->GetType() != SMESH::VOLUME )
6073 //        THROW_SALOME_CORBA_EXCEPTION("Not a volume group", SALOME::BAD_PARAM);
6074       SMESH::long_array_var anIDs = aGrp->GetIDs();
6075       arrayToSet( anIDs, aMeshDS, domains[ i ], SMDSAbs_All );
6076     }
6077   }
6078
6079   isOK = getEditor().DoubleNodesOnGroupBoundaries( domains, createJointElems, onAllBoundaries );
6080   // TODO publish the groups of flat elements in study
6081
6082   declareMeshModified( /*isReComputeSafe=*/ !isOK );
6083
6084   // Update Python script
6085   TPythonDump() << "isDone = " << this << ".DoubleNodesOnGroupBoundaries( " << &theDomains
6086                 << ", " << createJointElems << ", " << onAllBoundaries << " )";
6087
6088   SMESH_CATCH( SMESH::throwCorbaException );
6089
6090   myMesh_i->CreateGroupServants(); // publish created groups if any
6091
6092   return isOK;
6093 }
6094
6095 //================================================================================
6096 /*!
6097  * \brief Double nodes on some external faces and create flat elements.
6098  * Flat elements are mainly used by some types of mechanic calculations.
6099  *
6100  * Each group of the list must be constituted of faces.
6101  * Triangles are transformed in prisms, and quadrangles in hexahedrons.
6102  * @param theGroupsOfFaces - list of groups of faces
6103  * @return TRUE if operation has been completed successfully, FALSE otherwise
6104  */
6105 //================================================================================
6106
6107 CORBA::Boolean
6108 SMESH_MeshEditor_i::CreateFlatElementsOnFacesGroups( const SMESH::ListOfGroups& theGroupsOfFaces )
6109   throw (SALOME::SALOME_Exception)
6110 {
6111   SMESH_TRY;
6112   initData();
6113
6114   SMESHDS_Mesh* aMeshDS = getMeshDS();
6115
6116   vector<TIDSortedElemSet> faceGroups;
6117   faceGroups.clear();
6118
6119   for ( int i = 0, n = theGroupsOfFaces.length(); i < n; i++ )
6120   {
6121     SMESH::SMESH_GroupBase_var aGrp = theGroupsOfFaces[ i ];
6122     if ( !CORBA::is_nil( aGrp ) && ( aGrp->GetType() != SMESH::NODE ) )
6123     {
6124       TIDSortedElemSet faceGroup;
6125       faceGroup.clear();
6126       faceGroups.push_back(faceGroup);
6127       SMESH::long_array_var anIDs = aGrp->GetIDs();
6128       arrayToSet( anIDs, aMeshDS, faceGroups[ i ], SMDSAbs_All );
6129     }
6130   }
6131
6132   bool aResult = getEditor().CreateFlatElementsOnFacesGroups( faceGroups );
6133   // TODO publish the groups of flat elements in study
6134
6135   declareMeshModified( /*isReComputeSafe=*/ !aResult );
6136
6137   // Update Python script
6138   TPythonDump() << this << ".CreateFlatElementsOnFacesGroups( " << &theGroupsOfFaces << " )";
6139   return aResult;
6140
6141   SMESH_CATCH( SMESH::throwCorbaException );
6142   return false;
6143 }
6144
6145 //================================================================================
6146 /*!
6147  *  \brief Identify all the elements around a geom shape, get the faces delimiting
6148  *         the hole.
6149  *
6150  *  Build groups of volume to remove, groups of faces to replace on the skin of the
6151  *  object, groups of faces to remove inside the object, (idem edges).
6152  *  Build ordered list of nodes at the border of each group of faces to replace
6153  *  (to be used to build a geom subshape).
6154  */
6155 //================================================================================
6156
6157 void SMESH_MeshEditor_i::CreateHoleSkin(CORBA::Double                  radius,
6158                                         GEOM::GEOM_Object_ptr          theShape,
6159                                         const char*                    groupName,
6160                                         const SMESH::double_array&     theNodesCoords,
6161                                         SMESH::array_of_long_array_out GroupsOfNodes)
6162   throw (SALOME::SALOME_Exception)
6163 {
6164   SMESH_TRY;
6165
6166   initData();
6167   std::vector<std::vector<int> > aListOfListOfNodes;
6168   ::SMESH_MeshEditor aMeshEditor( myMesh );
6169
6170   theSearchersDeleter.Set( myMesh ); // remove theNodeSearcher if mesh is other
6171   if ( !theNodeSearcher )
6172     theNodeSearcher = SMESH_MeshAlgos::GetNodeSearcher( *getMeshDS() );
6173
6174   vector<double> nodesCoords;
6175   for (int i = 0; i < theNodesCoords.length(); i++)
6176   {
6177     nodesCoords.push_back( theNodesCoords[i] );
6178   }
6179
6180   TopoDS_Shape aShape = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape( theShape );
6181   aMeshEditor.CreateHoleSkin(radius, aShape, theNodeSearcher, groupName,
6182                              nodesCoords, aListOfListOfNodes);
6183
6184   GroupsOfNodes = new SMESH::array_of_long_array;
6185   GroupsOfNodes->length( aListOfListOfNodes.size() );
6186   std::vector<std::vector<int> >::iterator llIt = aListOfListOfNodes.begin();
6187   for ( CORBA::Long i = 0; llIt != aListOfListOfNodes.end(); llIt++, i++ )
6188   {
6189     vector<int>& aListOfNodes = *llIt;
6190     vector<int>::iterator lIt = aListOfNodes.begin();;
6191     SMESH::long_array& aGroup = (*GroupsOfNodes)[ i ];
6192     aGroup.length( aListOfNodes.size() );
6193     for ( int j = 0; lIt != aListOfNodes.end(); lIt++, j++ )
6194       aGroup[ j ] = (*lIt);
6195   }
6196   TPythonDump() << "lists_nodes = " << this << ".CreateHoleSkin( "
6197                 << radius << ", "
6198                 << theShape
6199                 << ", '" << groupName << "', "
6200                 << theNodesCoords << " )";
6201
6202   SMESH_CATCH( SMESH::throwCorbaException );
6203 }
6204
6205 // issue 20749 ===================================================================
6206 /*!
6207  * \brief Creates missing boundary elements
6208  *  \param elements - elements whose boundary is to be checked
6209  *  \param dimension - defines type of boundary elements to create
6210  *  \param groupName - a name of group to store created boundary elements in,
6211  *                     "" means not to create the group
6212  *  \param meshName - a name of new mesh to store created boundary elements in,
6213  *                     "" means not to create the new mesh
6214  *  \param toCopyElements - if true, the checked elements will be copied into the new mesh
6215  *  \param toCopyExistingBondary - if true, not only new but also pre-existing
6216  *                                boundary elements will be copied into the new mesh
6217  *  \param group - returns the create group, if any
6218  *  \retval SMESH::SMESH_Mesh - the mesh where elements were added to
6219  */
6220 // ================================================================================
6221
6222 SMESH::SMESH_Mesh_ptr
6223 SMESH_MeshEditor_i::MakeBoundaryMesh(SMESH::SMESH_IDSource_ptr idSource,
6224                                      SMESH::Bnd_Dimension      dim,
6225                                      const char*               groupName,
6226                                      const char*               meshName,
6227                                      CORBA::Boolean            toCopyElements,
6228                                      CORBA::Boolean            toCopyExistingBondary,
6229                                      SMESH::SMESH_Group_out    group)
6230   throw (SALOME::SALOME_Exception)
6231 {
6232   SMESH_TRY;
6233   initData();
6234
6235   if ( dim > SMESH::BND_1DFROM2D )
6236     THROW_SALOME_CORBA_EXCEPTION("Invalid boundary dimension", SALOME::BAD_PARAM);
6237
6238   SMESHDS_Mesh* aMeshDS = getMeshDS();
6239
6240   SMESH::SMESH_Mesh_var mesh_var;
6241   SMESH::SMESH_Group_var group_var;
6242
6243   TPythonDump pyDump;
6244
6245   TIDSortedElemSet elements;
6246   SMDSAbs_ElementType elemType = (dim == SMESH::BND_1DFROM2D) ? SMDSAbs_Face : SMDSAbs_Volume;
6247   if ( idSourceToSet( idSource, aMeshDS, elements, elemType,/*emptyIfIsMesh=*/true ))
6248   {
6249     // mesh to fill in
6250     mesh_var =
6251       strlen(meshName) ? makeMesh(meshName) : SMESH::SMESH_Mesh::_duplicate(myMesh_i->_this());
6252     SMESH_Mesh_i* mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh_var );
6253     // other mesh
6254     SMESH_Mesh* smesh_mesh = (mesh_i==myMesh_i) ? (SMESH_Mesh*)0 : &mesh_i->GetImpl();
6255
6256     // group of new boundary elements
6257     SMESH_Group* smesh_group = 0;
6258     if ( strlen(groupName) )
6259     {
6260       group_var = mesh_i->CreateGroup( SMESH::ElementType(int(elemType)-1),groupName);
6261       if ( SMESH_GroupBase_i* group_i = SMESH::DownCast<SMESH_GroupBase_i*>( group_var ))
6262         smesh_group = group_i->GetSmeshGroup();
6263     }
6264
6265     // do it
6266     getEditor().MakeBoundaryMesh( elements,
6267                                   ::SMESH_MeshEditor::Bnd_Dimension(dim),
6268                                   smesh_group,
6269                                   smesh_mesh,
6270                                   toCopyElements,
6271                                   toCopyExistingBondary);
6272
6273     if ( smesh_mesh )
6274       smesh_mesh->GetMeshDS()->Modified();
6275   }
6276
6277   const char* dimName[] = { "BND_2DFROM3D", "BND_1DFROM3D", "BND_1DFROM2D" };
6278
6279   // result of MakeBoundaryMesh() is a tuple (mesh, group)
6280   if ( mesh_var->_is_nil() )
6281     pyDump << myMesh_i->_this() << ", ";
6282   else
6283     pyDump << mesh_var << ", ";
6284   if ( group_var->_is_nil() )
6285     pyDump << "_NoneGroup = "; // assignment to None is forbiden
6286   else
6287     pyDump << group_var << " = ";
6288   pyDump << this << ".MakeBoundaryMesh( "
6289          << idSource << ", "
6290          << "SMESH." << dimName[int(dim)] << ", "
6291          << "'" << groupName << "', "
6292          << "'" << meshName<< "', "
6293          << toCopyElements << ", "
6294          << toCopyExistingBondary << ")";
6295
6296   group = group_var._retn();
6297   return mesh_var._retn();
6298
6299   SMESH_CATCH( SMESH::throwCorbaException );
6300   return SMESH::SMESH_Mesh::_nil();
6301 }
6302
6303 //================================================================================
6304 /*!
6305  * \brief Creates missing boundary elements
6306  *  \param dimension - defines type of boundary elements to create
6307  *  \param groupName - a name of group to store all boundary elements in,
6308  *    "" means not to create the group
6309  *  \param meshName - a name of a new mesh, which is a copy of the initial 
6310  *    mesh + created boundary elements; "" means not to create the new mesh
6311  *  \param toCopyAll - if true, the whole initial mesh will be copied into
6312  *    the new mesh else only boundary elements will be copied into the new mesh
6313  *  \param groups - optional groups of elements to make boundary around
6314  *  \param mesh - returns the mesh where elements were added to
6315  *  \param group - returns the created group, if any
6316  *  \retval long - number of added boundary elements
6317  */
6318 //================================================================================
6319
6320 CORBA::Long SMESH_MeshEditor_i::MakeBoundaryElements(SMESH::Bnd_Dimension dim,
6321                                                      const char* groupName,
6322                                                      const char* meshName,
6323                                                      CORBA::Boolean toCopyAll,
6324                                                      const SMESH::ListOfIDSources& groups,
6325                                                      SMESH::SMESH_Mesh_out mesh,
6326                                                      SMESH::SMESH_Group_out group)
6327   throw (SALOME::SALOME_Exception)
6328 {
6329   SMESH_TRY;
6330   initData();
6331
6332   if ( dim > SMESH::BND_1DFROM2D )
6333     THROW_SALOME_CORBA_EXCEPTION("Invalid boundary dimension", SALOME::BAD_PARAM);
6334
6335   // separate groups belonging to this and other mesh
6336   SMESH::ListOfIDSources_var groupsOfThisMesh = new SMESH::ListOfIDSources;
6337   SMESH::ListOfIDSources_var groupsOfOtherMesh = new SMESH::ListOfIDSources;
6338   groupsOfThisMesh->length( groups.length() );
6339   groupsOfOtherMesh->length( groups.length() );
6340   int nbGroups = 0, nbGroupsOfOtherMesh = 0;
6341   for ( int i = 0; i < groups.length(); ++i )
6342   {
6343     SMESH::SMESH_Mesh_var m = groups[i]->GetMesh();
6344     if ( myMesh_i != SMESH::DownCast<SMESH_Mesh_i*>( m ))
6345       groupsOfOtherMesh[ nbGroupsOfOtherMesh++ ] = groups[i];
6346     else
6347       groupsOfThisMesh[ nbGroups++ ] = groups[i];
6348     if ( SMESH::DownCast<SMESH_Mesh_i*>( groups[i] ))
6349       THROW_SALOME_CORBA_EXCEPTION("expect a group but recieve a mesh", SALOME::BAD_PARAM);
6350   }
6351   groupsOfThisMesh->length( nbGroups );
6352   groupsOfOtherMesh->length( nbGroupsOfOtherMesh );
6353
6354   int nbAdded = 0;
6355   TPythonDump pyDump;
6356
6357   if ( nbGroupsOfOtherMesh > 0 )
6358   {
6359     // process groups belonging to another mesh
6360     SMESH::SMESH_Mesh_var    otherMesh = groupsOfOtherMesh[0]->GetMesh();
6361     SMESH::SMESH_MeshEditor_var editor = otherMesh->GetMeshEditor();
6362     nbAdded += editor->MakeBoundaryElements( dim, groupName, meshName, toCopyAll,
6363                                              groupsOfOtherMesh, mesh, group );
6364   }
6365
6366   SMESH::SMESH_Mesh_var mesh_var;
6367   SMESH::SMESH_Group_var group_var;
6368
6369   // get mesh to fill
6370   mesh_var = SMESH::SMESH_Mesh::_duplicate( myMesh_i->_this() );
6371   const bool toCopyMesh = ( strlen( meshName ) > 0 );
6372   if ( toCopyMesh )
6373   {
6374     if ( toCopyAll )
6375       mesh_var = SMESH_Gen_i::GetSMESHGen()->CopyMesh(mesh_var,
6376                                                       meshName,
6377                                                       /*toCopyGroups=*/false,
6378                                                       /*toKeepIDs=*/true);
6379     else
6380       mesh_var = makeMesh(meshName);
6381   }
6382   SMESH_Mesh_i* mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh_var );
6383   SMESH_Mesh*  tgtMesh = &mesh_i->GetImpl();
6384
6385   // source mesh
6386   SMESH_Mesh*     srcMesh = ( toCopyMesh && !toCopyAll ) ? myMesh : tgtMesh;
6387   SMESHDS_Mesh* srcMeshDS = srcMesh->GetMeshDS();
6388
6389   // group of boundary elements
6390   SMESH_Group* smesh_group = 0;
6391   SMDSAbs_ElementType elemType = (dim == SMESH::BND_2DFROM3D) ? SMDSAbs_Volume : SMDSAbs_Face;
6392   if ( strlen(groupName) )
6393   {
6394     SMESH::ElementType groupType = SMESH::ElementType( int(elemType)-1 );
6395     group_var = mesh_i->CreateGroup( groupType, groupName );
6396     if ( SMESH_GroupBase_i* group_i = SMESH::DownCast<SMESH_GroupBase_i*>( group_var ))
6397       smesh_group = group_i->GetSmeshGroup();
6398   }
6399
6400   TIDSortedElemSet elements;
6401
6402   if ( groups.length() > 0 )
6403   {
6404     for ( int i = 0; i < nbGroups; ++i )
6405     {
6406       elements.clear();
6407       if ( idSourceToSet( groupsOfThisMesh[i], srcMeshDS, elements, elemType,/*emptyIfIsMesh=*/0 ))
6408       {
6409         SMESH::Bnd_Dimension bdim = 
6410           ( elemType == SMDSAbs_Volume ) ? SMESH::BND_2DFROM3D : SMESH::BND_1DFROM2D;
6411         nbAdded += getEditor().MakeBoundaryMesh( elements,
6412                                                  ::SMESH_MeshEditor::Bnd_Dimension(bdim),
6413                                                  smesh_group,
6414                                                  tgtMesh,
6415                                                  /*toCopyElements=*/false,
6416                                                  /*toCopyExistingBondary=*/srcMesh != tgtMesh,
6417                                                  /*toAddExistingBondary=*/true,
6418                                                  /*aroundElements=*/true);
6419       }
6420     }
6421   }
6422   else
6423   {
6424     nbAdded += getEditor().MakeBoundaryMesh( elements,
6425                                              ::SMESH_MeshEditor::Bnd_Dimension(dim),
6426                                              smesh_group,
6427                                              tgtMesh,
6428                                              /*toCopyElements=*/false,
6429                                              /*toCopyExistingBondary=*/srcMesh != tgtMesh,
6430                                              /*toAddExistingBondary=*/true);
6431   }
6432   tgtMesh->GetMeshDS()->Modified();
6433
6434   const char* dimName[] = { "BND_2DFROM3D", "BND_1DFROM3D", "BND_1DFROM2D" };
6435
6436   // result of MakeBoundaryElements() is a tuple (nb, mesh, group)
6437   pyDump << "nbAdded, ";
6438   if ( mesh_var->_is_nil() )
6439     pyDump << myMesh_i->_this() << ", ";
6440   else
6441     pyDump << mesh_var << ", ";
6442   if ( group_var->_is_nil() )
6443     pyDump << "_NoneGroup = "; // assignment to None is forbiden
6444   else
6445     pyDump << group_var << " = ";
6446   pyDump << this << ".MakeBoundaryElements( "
6447          << "SMESH." << dimName[int(dim)] << ", "
6448          << "'" << groupName << "', "
6449          << "'" << meshName<< "', "
6450          << toCopyAll << ", "
6451          << groups << ")";
6452
6453   mesh  = mesh_var._retn();
6454   group = group_var._retn();
6455   return nbAdded;
6456
6457   SMESH_CATCH( SMESH::throwCorbaException );
6458   return 0;
6459 }