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