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