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