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