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