Salome HOME
22573: [CEA 1154] Regression on a blsurf mesh (crash on test_periodicity_LR_ONLY.py)
[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 infulence
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   if ( myIsPreviewMode )
2528   {
2529     SMDSAbs_ElementType previewType = SMDSAbs_All; //SMDSAbs_Face;
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();
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()->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   if ( myIsPreviewMode )
2611   {
2612     SMDSAbs_ElementType previewType = SMDSAbs_Face;
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()->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   TIDSortedElemSet elems;
4801   bool elemsOK;
4802   if ( !( elemsOK = CORBA::is_nil( theObject )))
4803   {
4804     elemsOK =  idSourceToSet( theObject, getMeshDS(), elems,
4805                               SMDSAbs_All, /*emptyIfIsMesh=*/true );
4806   }
4807   if ( elemsOK )
4808   {
4809     if ( !elems.empty() && (*elems.begin())->GetType() == SMDSAbs_Node )
4810       THROW_SALOME_CORBA_EXCEPTION("Group of nodes is not allowed", SALOME::BAD_PARAM);
4811
4812     if ( elems.empty() ) getEditor().ConvertToQuadratic(theForce3d, theToBiQuad);
4813     else                 getEditor().ConvertToQuadratic(theForce3d, elems, theToBiQuad);
4814
4815     declareMeshModified( /*isReComputeSafe=*/false );
4816   }
4817
4818   SMESH_CATCH( SMESH::throwCorbaException );
4819 }
4820
4821 //=======================================================================
4822 //function : ConvertFromQuadratic
4823 //purpose  :
4824 //=======================================================================
4825
4826 CORBA::Boolean SMESH_MeshEditor_i::ConvertFromQuadratic()
4827   throw (SALOME::SALOME_Exception)
4828 {
4829   CORBA::Boolean isDone = getEditor().ConvertFromQuadratic();
4830   TPythonDump() << this << ".ConvertFromQuadratic()";
4831   declareMeshModified( /*isReComputeSafe=*/!isDone );
4832   return isDone;
4833 }
4834
4835 //=======================================================================
4836 //function : ConvertToQuadratic
4837 //purpose  :
4838 //=======================================================================
4839
4840 void SMESH_MeshEditor_i::ConvertToQuadratic(CORBA::Boolean theForce3d)
4841   throw (SALOME::SALOME_Exception)
4842 {
4843   convertToQuadratic( theForce3d, false );
4844   TPythonDump() << this << ".ConvertToQuadratic("<<theForce3d<<")";
4845 }
4846
4847 //================================================================================
4848 /*!
4849  * \brief Makes a part of the mesh quadratic
4850  */
4851 //================================================================================
4852
4853 void SMESH_MeshEditor_i::ConvertToQuadraticObject(CORBA::Boolean            theForce3d,
4854                                                   SMESH::SMESH_IDSource_ptr theObject)
4855   throw (SALOME::SALOME_Exception)
4856 {
4857   convertToQuadratic( theForce3d, false, theObject );
4858   TPythonDump() << this << ".ConvertToQuadraticObject("<<theForce3d<<", "<<theObject<<")";
4859 }
4860
4861 //================================================================================
4862 /*!
4863  * \brief Makes a part of the mesh bi-quadratic
4864  */
4865 //================================================================================
4866
4867 void SMESH_MeshEditor_i::ConvertToBiQuadratic(CORBA::Boolean            theForce3d,
4868                                               SMESH::SMESH_IDSource_ptr theObject)
4869   throw (SALOME::SALOME_Exception)
4870 {
4871   convertToQuadratic( theForce3d, true, theObject );
4872   TPythonDump() << this << ".ConvertToBiQuadratic("<<theForce3d<<", "<<theObject<<")";
4873 }
4874
4875 //================================================================================
4876 /*!
4877  * \brief Makes a part of the mesh linear
4878  */
4879 //================================================================================
4880
4881 void SMESH_MeshEditor_i::ConvertFromQuadraticObject(SMESH::SMESH_IDSource_ptr theObject)
4882   throw (SALOME::SALOME_Exception)
4883 {
4884   SMESH_TRY;
4885
4886   TPythonDump pyDump;
4887
4888   TIDSortedElemSet elems;
4889   if ( idSourceToSet( theObject, getMeshDS(), elems, SMDSAbs_All, /*emptyIfIsMesh=*/true ))
4890   {
4891     if ( elems.empty() )
4892     {
4893       ConvertFromQuadratic();
4894     }
4895     else if ( (*elems.begin())->GetType() == SMDSAbs_Node )
4896     {
4897       THROW_SALOME_CORBA_EXCEPTION("Group of nodes is not allowed", SALOME::BAD_PARAM);
4898     }
4899     else
4900     {
4901       getEditor().ConvertFromQuadratic(elems);
4902     }
4903   }
4904   declareMeshModified( /*isReComputeSafe=*/false );
4905
4906   pyDump << this << ".ConvertFromQuadraticObject( "<<theObject<<" )";
4907
4908   SMESH_CATCH( SMESH::throwCorbaException );
4909 }
4910
4911 //=======================================================================
4912 //function : makeMesh
4913 //purpose  : create a named imported mesh
4914 //=======================================================================
4915
4916 SMESH::SMESH_Mesh_ptr SMESH_MeshEditor_i::makeMesh(const char* theMeshName)
4917 {
4918   SMESH_Gen_i*              gen = SMESH_Gen_i::GetSMESHGen();
4919   SMESH::SMESH_Mesh_var    mesh = gen->CreateEmptyMesh();
4920   SALOMEDS::Study_var     study = gen->GetCurrentStudy();
4921   SALOMEDS::SObject_wrap meshSO = gen->ObjectToSObject( study, mesh );
4922   gen->SetName( meshSO, theMeshName, "Mesh" );
4923   gen->SetPixMap( meshSO, "ICON_SMESH_TREE_MESH_IMPORTED");
4924
4925   return mesh._retn();
4926 }
4927
4928 //=======================================================================
4929 //function : dumpGroupsList
4930 //purpose  :
4931 //=======================================================================
4932
4933 void SMESH_MeshEditor_i::dumpGroupsList(TPythonDump &               theDumpPython,
4934                                         const SMESH::ListOfGroups * theGroupList)
4935 {
4936   bool isDumpGroupList = ( theGroupList && theGroupList->length() > 0 );
4937   if ( isDumpGroupList )
4938     theDumpPython << theGroupList << " = ";
4939 }
4940
4941 //================================================================================
4942 /*!
4943   \brief Generates the unique group name.
4944   \param thePrefix name prefix
4945   \return unique name
4946 */
4947 //================================================================================
4948
4949 string SMESH_MeshEditor_i::generateGroupName(const string& thePrefix)
4950 {
4951   SMESH::ListOfGroups_var groups = myMesh_i->GetGroups();
4952   set<string> groupNames;
4953
4954   // Get existing group names
4955   for (int i = 0, nbGroups = groups->length(); i < nbGroups; i++ ) {
4956     SMESH::SMESH_GroupBase_var aGroup = groups[i];
4957     if (CORBA::is_nil(aGroup))
4958       continue;
4959
4960     CORBA::String_var name = aGroup->GetName();
4961     groupNames.insert( name.in() );
4962   }
4963
4964   // Find new name
4965   string name = thePrefix;
4966   int index = 0;
4967
4968   while (!groupNames.insert(name).second)
4969     name = SMESH_Comment( thePrefix ) << "_" << index++;
4970
4971   return name;
4972 }
4973
4974 //================================================================================
4975 /*!
4976  * \brief Prepare SMESH_IDSource for work
4977  */
4978 //================================================================================
4979
4980 void SMESH_MeshEditor_i::prepareIdSource(SMESH::SMESH_IDSource_ptr theObject)
4981 {
4982   if ( SMESH::Filter_i* filter = SMESH::DownCast<SMESH::Filter_i*>( theObject ))
4983   {
4984     SMESH::SMESH_Mesh_var mesh = myMesh_i->_this();
4985     filter->SetMesh( mesh );
4986   }
4987 }
4988 //================================================================================
4989 /*!
4990  * \brief Retrieve elements of given type from SMESH_IDSource
4991  */
4992 //================================================================================
4993
4994 bool SMESH_MeshEditor_i::idSourceToSet(SMESH::SMESH_IDSource_ptr  theIDSource,
4995                                        const SMESHDS_Mesh*        theMeshDS,
4996                                        TIDSortedElemSet&          theElemSet,
4997                                        const SMDSAbs_ElementType  theType,
4998                                        const bool                 emptyIfIsMesh,
4999                                        IDSource_Error*            error)
5000
5001 {
5002   if ( error ) *error = IDSource_OK;
5003
5004   if ( CORBA::is_nil( theIDSource ) )
5005   {
5006     if ( error ) *error = IDSource_INVALID;
5007     return false;
5008   }
5009   if ( emptyIfIsMesh && SMESH::DownCast<SMESH_Mesh_i*>( theIDSource ))
5010   {
5011     if ( error && getMeshDS()->GetMeshInfo().NbElements( theType ) == 0 )
5012       *error = IDSource_EMPTY;
5013     return true;
5014   }
5015   prepareIdSource( theIDSource );
5016   SMESH::long_array_var anIDs = theIDSource->GetIDs();
5017   if ( anIDs->length() == 0 )
5018   {
5019     if ( error ) *error = IDSource_EMPTY;
5020     return false;
5021   }
5022   SMESH::array_of_ElementType_var types = theIDSource->GetTypes();
5023   if ( types->length() == 1 && types[0] == SMESH::NODE ) // group of nodes
5024   {
5025     if ( theType == SMDSAbs_All || theType == SMDSAbs_Node )
5026     {
5027       arrayToSet( anIDs, getMeshDS(), theElemSet, SMDSAbs_Node );
5028     }
5029     else
5030     {
5031       if ( error ) *error = IDSource_INVALID;
5032       return false;
5033     }
5034   }
5035   else
5036   {
5037     arrayToSet( anIDs, getMeshDS(), theElemSet, theType);
5038     if ( bool(anIDs->length()) != bool(theElemSet.size()))
5039     {
5040       if ( error ) *error = IDSource_INVALID;
5041       return false;
5042     }
5043   }
5044   return true;
5045 }
5046
5047 //================================================================================
5048 /*!
5049  * \brief Duplicates given elements, i.e. creates new elements based on the
5050  *        same nodes as the given ones.
5051  * \param theElements - container of elements to duplicate.
5052  * \param theGroupName - a name of group to contain the generated elements.
5053  *                    If a group with such a name already exists, the new elements
5054  *                    are added to the existng group, else a new group is created.
5055  *                    If \a theGroupName is empty, new elements are not added 
5056  *                    in any group.
5057  * \return a group where the new elements are added. NULL if theGroupName == "".
5058  * \sa DoubleNode()
5059  */
5060 //================================================================================
5061
5062 SMESH::SMESH_Group_ptr
5063 SMESH_MeshEditor_i::DoubleElements(SMESH::SMESH_IDSource_ptr theElements,
5064                                    const char*               theGroupName)
5065   throw (SALOME::SALOME_Exception)
5066 {
5067   SMESH::SMESH_Group_var newGroup;
5068
5069   SMESH_TRY;
5070   initData();
5071
5072   TPythonDump pyDump;
5073
5074   TIDSortedElemSet elems;
5075   if ( idSourceToSet( theElements, getMeshDS(), elems, SMDSAbs_All, /*emptyIfIsMesh=*/true))
5076   {
5077     getEditor().DoubleElements( elems );
5078
5079     if ( strlen( theGroupName ) && !getEditor().GetLastCreatedElems().IsEmpty() )
5080     {
5081       // group type
5082       SMESH::ElementType type =
5083         SMESH::ElementType( getEditor().GetLastCreatedElems().Value(1)->GetType() );
5084       // find existing group
5085       SMESH::ListOfGroups_var groups = myMesh_i->GetGroups();
5086       for ( size_t i = 0; i < groups->length(); ++i )
5087         if ( groups[i]->GetType() == type )
5088         {
5089           CORBA::String_var name = groups[i]->GetName();
5090           if ( strcmp( name, theGroupName ) == 0 ) {
5091             newGroup = SMESH::SMESH_Group::_narrow( groups[i] );
5092             break;
5093           }
5094         }
5095       // create a new group
5096       if ( newGroup->_is_nil() )
5097         newGroup = myMesh_i->CreateGroup( type, theGroupName );
5098       // fill newGroup
5099       if ( SMESH_Group_i* group_i = SMESH::DownCast< SMESH_Group_i* >( newGroup ))
5100       {
5101         SMESHDS_Group* groupDS = static_cast< SMESHDS_Group* >( group_i->GetGroupDS() );
5102         const SMESH_SequenceOfElemPtr& aSeq = getEditor().GetLastCreatedElems();
5103         for ( int i = 1; i <= aSeq.Length(); i++ )
5104           groupDS->SMDSGroup().Add( aSeq(i) );
5105       }
5106     }
5107   }
5108   // python dump
5109   if ( !newGroup->_is_nil() )
5110     pyDump << newGroup << " = ";
5111   pyDump << this << ".DoubleElements( "
5112          << theElements << ", " << "'" << theGroupName <<"')";
5113
5114   SMESH_CATCH( SMESH::throwCorbaException );
5115
5116   return newGroup._retn();
5117 }
5118
5119 //================================================================================
5120 /*!
5121   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5122   \param theNodes - identifiers of nodes to be doubled
5123   \param theModifiedElems - identifiers of elements to be updated by the new (doubled)
5124          nodes. If list of element identifiers is empty then nodes are doubled but
5125          they not assigned to elements
5126   \return TRUE if operation has been completed successfully, FALSE otherwise
5127   \sa DoubleNode(), DoubleNodeGroup(), DoubleNodeGroups()
5128 */
5129 //================================================================================
5130
5131 CORBA::Boolean SMESH_MeshEditor_i::DoubleNodes( const SMESH::long_array& theNodes,
5132                                                 const SMESH::long_array& theModifiedElems )
5133   throw (SALOME::SALOME_Exception)
5134 {
5135   SMESH_TRY;
5136   initData();
5137
5138   list< int > aListOfNodes;
5139   int i, n;
5140   for ( i = 0, n = theNodes.length(); i < n; i++ )
5141     aListOfNodes.push_back( theNodes[ i ] );
5142
5143   list< int > aListOfElems;
5144   for ( i = 0, n = theModifiedElems.length(); i < n; i++ )
5145     aListOfElems.push_back( theModifiedElems[ i ] );
5146
5147   bool aResult = getEditor().DoubleNodes( aListOfNodes, aListOfElems );
5148
5149   declareMeshModified( /*isReComputeSafe=*/ !aResult );
5150
5151   // Update Python script
5152   TPythonDump() << this << ".DoubleNodes( " << theNodes << ", "<< theModifiedElems << " )";
5153
5154   return aResult;
5155
5156   SMESH_CATCH( SMESH::throwCorbaException );
5157   return 0;
5158 }
5159
5160 //================================================================================
5161 /*!
5162   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5163   This method provided for convenience works as DoubleNodes() described above.
5164   \param theNodeId - identifier of node to be doubled.
5165   \param theModifiedElems - identifiers of elements to be updated.
5166   \return TRUE if operation has been completed successfully, FALSE otherwise
5167   \sa DoubleNodes(), DoubleNodeGroup(), DoubleNodeGroups()
5168 */
5169 //================================================================================
5170
5171 CORBA::Boolean SMESH_MeshEditor_i::DoubleNode( CORBA::Long              theNodeId,
5172                                                const SMESH::long_array& theModifiedElems )
5173   throw (SALOME::SALOME_Exception)
5174 {
5175   SMESH_TRY;
5176   SMESH::long_array_var aNodes = new SMESH::long_array;
5177   aNodes->length( 1 );
5178   aNodes[ 0 ] = theNodeId;
5179
5180   TPythonDump pyDump; // suppress dump by the next line
5181
5182   CORBA::Boolean done = DoubleNodes( aNodes, theModifiedElems );
5183
5184   pyDump << this << ".DoubleNode( " << theNodeId << ", " << theModifiedElems << " )";
5185
5186   return done;
5187
5188   SMESH_CATCH( SMESH::throwCorbaException );
5189   return 0;
5190 }
5191
5192 //================================================================================
5193 /*!
5194   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5195   This method provided for convenience works as DoubleNodes() described above.
5196   \param theNodes - group of nodes to be doubled.
5197   \param theModifiedElems - group of elements to be updated.
5198   \return TRUE if operation has been completed successfully, FALSE otherwise
5199   \sa DoubleNode(), DoubleNodes(), DoubleNodeGroups()
5200 */
5201 //================================================================================
5202
5203 CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeGroup(SMESH::SMESH_GroupBase_ptr theNodes,
5204                                                    SMESH::SMESH_GroupBase_ptr theModifiedElems )
5205   throw (SALOME::SALOME_Exception)
5206 {
5207   SMESH_TRY;
5208   if ( CORBA::is_nil( theNodes ) && theNodes->GetType() != SMESH::NODE )
5209     return false;
5210
5211   SMESH::long_array_var aNodes = theNodes->GetListOfID();
5212   SMESH::long_array_var aModifiedElems;
5213   if ( !CORBA::is_nil( theModifiedElems ) )
5214     aModifiedElems = theModifiedElems->GetListOfID();
5215   else
5216   {
5217     aModifiedElems = new SMESH::long_array;
5218     aModifiedElems->length( 0 );
5219   }
5220
5221   TPythonDump pyDump; // suppress dump by the next line
5222
5223   bool done = DoubleNodes( aNodes, aModifiedElems );
5224
5225   pyDump << this << ".DoubleNodeGroup( " << theNodes << ", " << theModifiedElems << " )";
5226
5227   return done;
5228
5229   SMESH_CATCH( SMESH::throwCorbaException );
5230   return 0;
5231 }
5232
5233 //================================================================================
5234 /*!
5235  * \brief Creates a hole in a mesh by doubling the nodes of some particular elements.
5236  * Works as DoubleNodeGroup(), but returns a new group with newly created nodes.
5237  * \param theNodes - group of nodes to be doubled.
5238  * \param theModifiedElems - group of elements to be updated.
5239  * \return a new group with newly created nodes
5240  * \sa DoubleNodeGroup()
5241  */
5242 //================================================================================
5243
5244 SMESH::SMESH_Group_ptr
5245 SMESH_MeshEditor_i::DoubleNodeGroupNew( SMESH::SMESH_GroupBase_ptr theNodes,
5246                                         SMESH::SMESH_GroupBase_ptr theModifiedElems )
5247   throw (SALOME::SALOME_Exception)
5248 {
5249   SMESH_TRY;
5250   SMESH::SMESH_Group_var aNewGroup;
5251
5252   if ( CORBA::is_nil( theNodes ) && theNodes->GetType() != SMESH::NODE )
5253     return aNewGroup._retn();
5254
5255   // Duplicate nodes
5256   SMESH::long_array_var aNodes = theNodes->GetListOfID();
5257   SMESH::long_array_var aModifiedElems;
5258   if ( !CORBA::is_nil( theModifiedElems ) )
5259     aModifiedElems = theModifiedElems->GetListOfID();
5260   else {
5261     aModifiedElems = new SMESH::long_array;
5262     aModifiedElems->length( 0 );
5263   }
5264
5265   TPythonDump pyDump; // suppress dump by the next line
5266
5267   bool aResult = DoubleNodes( aNodes, aModifiedElems );
5268   if ( aResult )
5269   {
5270     // Create group with newly created nodes
5271     SMESH::long_array_var anIds = GetLastCreatedNodes();
5272     if (anIds->length() > 0) {
5273       string anUnindexedName (theNodes->GetName());
5274       string aNewName = generateGroupName(anUnindexedName + "_double");
5275       aNewGroup = myMesh_i->CreateGroup(SMESH::NODE, aNewName.c_str());
5276       aNewGroup->Add(anIds);
5277       pyDump << aNewGroup << " = ";
5278     }
5279   }
5280
5281   pyDump << this << ".DoubleNodeGroupNew( " << theNodes << ", "
5282          << theModifiedElems << " )";
5283
5284   return aNewGroup._retn();
5285
5286   SMESH_CATCH( SMESH::throwCorbaException );
5287   return 0;
5288 }
5289
5290 //================================================================================
5291 /*!
5292   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5293   This method provided for convenience works as DoubleNodes() described above.
5294   \param theNodes - list of groups of nodes to be doubled
5295   \param theModifiedElems - list of groups of elements to be updated.
5296   \return TRUE if operation has been completed successfully, FALSE otherwise
5297   \sa DoubleNode(), DoubleNodeGroup(), DoubleNodes()
5298 */
5299 //================================================================================
5300
5301 CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeGroups(const SMESH::ListOfGroups& theNodes,
5302                                                     const SMESH::ListOfGroups& theModifiedElems )
5303   throw (SALOME::SALOME_Exception)
5304 {
5305   SMESH_TRY;
5306   initData();
5307
5308   std::list< int > aNodes;
5309   int i, n, j, m;
5310   for ( i = 0, n = theNodes.length(); i < n; i++ )
5311   {
5312     SMESH::SMESH_GroupBase_var aGrp = theNodes[ i ];
5313     if ( !CORBA::is_nil( aGrp ) && aGrp->GetType() == SMESH::NODE )
5314     {
5315       SMESH::long_array_var aCurr = aGrp->GetListOfID();
5316       for ( j = 0, m = aCurr->length(); j < m; j++ )
5317         aNodes.push_back( aCurr[ j ] );
5318     }
5319   }
5320
5321   std::list< int > anElems;
5322   for ( i = 0, n = theModifiedElems.length(); i < n; i++ )
5323   {
5324     SMESH::SMESH_GroupBase_var aGrp = theModifiedElems[ i ];
5325     if ( !CORBA::is_nil( aGrp ) && aGrp->GetType() != SMESH::NODE )
5326     {
5327       SMESH::long_array_var aCurr = aGrp->GetListOfID();
5328       for ( j = 0, m = aCurr->length(); j < m; j++ )
5329         anElems.push_back( aCurr[ j ] );
5330     }
5331   }
5332
5333   bool aResult = getEditor().DoubleNodes( aNodes, anElems );
5334
5335   declareMeshModified( /*isReComputeSafe=*/false );
5336
5337   TPythonDump() << this << ".DoubleNodeGroups( " << theNodes << ", " << theModifiedElems << " )";
5338
5339   return aResult;
5340
5341   SMESH_CATCH( SMESH::throwCorbaException );
5342   return 0;
5343 }
5344
5345 //================================================================================
5346 /*!
5347  * \brief Creates a hole in a mesh by doubling the nodes of some particular elements.
5348  * Works as DoubleNodeGroups(), but returns a new group with newly created nodes.
5349  * \param theNodes - group of nodes to be doubled.
5350  * \param theModifiedElems - group of elements to be updated.
5351  * \return a new group with newly created nodes
5352  * \sa DoubleNodeGroups()
5353  */
5354 //================================================================================
5355
5356 SMESH::SMESH_Group_ptr
5357 SMESH_MeshEditor_i::DoubleNodeGroupsNew( const SMESH::ListOfGroups& theNodes,
5358                                          const SMESH::ListOfGroups& theModifiedElems )
5359   throw (SALOME::SALOME_Exception)
5360 {
5361   SMESH::SMESH_Group_var aNewGroup;
5362
5363   TPythonDump pyDump; // suppress dump by the next line
5364
5365   bool aResult = DoubleNodeGroups( theNodes, theModifiedElems );
5366
5367   if ( aResult )
5368   {
5369     // Create group with newly created nodes
5370     SMESH::long_array_var anIds = GetLastCreatedNodes();
5371     if (anIds->length() > 0) {
5372       string anUnindexedName (theNodes[0]->GetName());
5373       string aNewName = generateGroupName(anUnindexedName + "_double");
5374       aNewGroup = myMesh_i->CreateGroup(SMESH::NODE, aNewName.c_str());
5375       aNewGroup->Add(anIds);
5376       pyDump << aNewGroup << " = ";
5377     }
5378   }
5379
5380   pyDump << this << ".DoubleNodeGroupsNew( " << theNodes << ", "
5381          << theModifiedElems << " )";
5382
5383   return aNewGroup._retn();
5384 }
5385
5386
5387 //================================================================================
5388 /*!
5389   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5390   \param theElems - the list of elements (edges or faces) to be replicated
5391   The nodes for duplication could be found from these elements
5392   \param theNodesNot - list of nodes to NOT replicate
5393   \param theAffectedElems - the list of elements (cells and edges) to which the
5394   replicated nodes should be associated to.
5395   \return TRUE if operation has been completed successfully, FALSE otherwise
5396   \sa DoubleNodeGroup(), DoubleNodeGroups()
5397 */
5398 //================================================================================
5399
5400 CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeElem( const SMESH::long_array& theElems,
5401                                                    const SMESH::long_array& theNodesNot,
5402                                                    const SMESH::long_array& theAffectedElems )
5403   throw (SALOME::SALOME_Exception)
5404 {
5405   SMESH_TRY;
5406   initData();
5407
5408   SMESHDS_Mesh* aMeshDS = getMeshDS();
5409   TIDSortedElemSet anElems, aNodes, anAffected;
5410   arrayToSet(theElems, aMeshDS, anElems, SMDSAbs_All);
5411   arrayToSet(theNodesNot, aMeshDS, aNodes, SMDSAbs_Node);
5412   arrayToSet(theAffectedElems, aMeshDS, anAffected, SMDSAbs_All);
5413
5414   bool aResult = getEditor().DoubleNodes( anElems, aNodes, anAffected );
5415
5416   // Update Python script
5417   TPythonDump() << this << ".DoubleNodeElem( " << theElems << ", "
5418                 << theNodesNot << ", " << theAffectedElems << " )";
5419
5420   declareMeshModified( /*isReComputeSafe=*/false );
5421   return aResult;
5422
5423   SMESH_CATCH( SMESH::throwCorbaException );
5424   return 0;
5425 }
5426
5427 //================================================================================
5428 /*!
5429   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5430   \param theElems - the list of elements (edges or faces) to be replicated
5431   The nodes for duplication could be found from these elements
5432   \param theNodesNot - list of nodes to NOT replicate
5433   \param theShape - shape to detect affected elements (element which geometric center
5434   located on or inside shape).
5435   The replicated nodes should be associated to affected elements.
5436   \return TRUE if operation has been completed successfully, FALSE otherwise
5437   \sa DoubleNodeGroupInRegion(), DoubleNodeGroupsInRegion()
5438 */
5439 //================================================================================
5440
5441 CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeElemInRegion ( const SMESH::long_array& theElems,
5442                                                             const SMESH::long_array& theNodesNot,
5443                                                             GEOM::GEOM_Object_ptr    theShape )
5444   throw (SALOME::SALOME_Exception)
5445 {
5446   SMESH_TRY;
5447   initData();
5448
5449
5450   SMESHDS_Mesh* aMeshDS = getMeshDS();
5451   TIDSortedElemSet anElems, aNodes;
5452   arrayToSet(theElems, aMeshDS, anElems, SMDSAbs_All);
5453   arrayToSet(theNodesNot, aMeshDS, aNodes, SMDSAbs_Node);
5454
5455   TopoDS_Shape aShape = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape( theShape );
5456   bool aResult = getEditor().DoubleNodesInRegion( anElems, aNodes, aShape );
5457
5458   // Update Python script
5459   TPythonDump() << "isDone = " << this << ".DoubleNodeElemInRegion( " << theElems << ", "
5460                 << theNodesNot << ", " << theShape << " )";
5461
5462   declareMeshModified( /*isReComputeSafe=*/false );
5463   return aResult;
5464
5465   SMESH_CATCH( SMESH::throwCorbaException );
5466   return 0;
5467 }
5468
5469 //================================================================================
5470 /*!
5471   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5472   \param theElems - group of of elements (edges or faces) to be replicated
5473   \param theNodesNot - group of nodes not to replicated
5474   \param theAffectedElems - group of elements to which the replicated nodes
5475   should be associated to.
5476   \return TRUE if operation has been completed successfully, FALSE otherwise
5477   \sa DoubleNodes(), DoubleNodeGroups()
5478 */
5479 //================================================================================
5480
5481 CORBA::Boolean
5482 SMESH_MeshEditor_i::DoubleNodeElemGroup(SMESH::SMESH_GroupBase_ptr theElems,
5483                                         SMESH::SMESH_GroupBase_ptr theNodesNot,
5484                                         SMESH::SMESH_GroupBase_ptr theAffectedElems)
5485   throw (SALOME::SALOME_Exception)
5486 {
5487   SMESH_TRY;
5488   if ( CORBA::is_nil( theElems ) && theElems->GetType() == SMESH::NODE )
5489     return false;
5490
5491   initData();
5492
5493
5494   SMESHDS_Mesh* aMeshDS = getMeshDS();
5495   TIDSortedElemSet anElems, aNodes, anAffected;
5496   idSourceToSet( theElems, aMeshDS, anElems, SMDSAbs_All );
5497   idSourceToSet( theNodesNot, aMeshDS, aNodes, SMDSAbs_Node );
5498   idSourceToSet( theAffectedElems, aMeshDS, anAffected, SMDSAbs_All );
5499
5500   bool aResult = getEditor().DoubleNodes( anElems, aNodes, anAffected );
5501
5502   // Update Python script
5503   TPythonDump() << "isDone = " << this << ".DoubleNodeElemGroup( " << theElems << ", "
5504                 << theNodesNot << ", " << theAffectedElems << " )";
5505
5506   declareMeshModified( /*isReComputeSafe=*/false );
5507   return aResult;
5508
5509   SMESH_CATCH( SMESH::throwCorbaException );
5510   return 0;
5511 }
5512
5513 //================================================================================
5514 /*!
5515  * \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5516  * Works as DoubleNodeElemGroup(), but returns a new group with newly created elements.
5517  * \param theElems - group of of elements (edges or faces) to be replicated
5518  * \param theNodesNot - group of nodes not to replicated
5519  * \param theAffectedElems - group of elements to which the replicated nodes
5520  *        should be associated to.
5521  * \return a new group with newly created elements
5522  * \sa DoubleNodeElemGroup()
5523  */
5524 //================================================================================
5525
5526 SMESH::SMESH_Group_ptr
5527 SMESH_MeshEditor_i::DoubleNodeElemGroupNew(SMESH::SMESH_GroupBase_ptr theElems,
5528                                            SMESH::SMESH_GroupBase_ptr theNodesNot,
5529                                            SMESH::SMESH_GroupBase_ptr theAffectedElems)
5530   throw (SALOME::SALOME_Exception)
5531 {
5532   TPythonDump pyDump;
5533   SMESH::ListOfGroups_var twoGroups = DoubleNodeElemGroup2New( theElems,
5534                                                                theNodesNot,
5535                                                                theAffectedElems,
5536                                                                true, false );
5537   SMESH::SMESH_GroupBase_var baseGroup = twoGroups[0].in();
5538   SMESH::SMESH_Group_var     elemGroup = SMESH::SMESH_Group::_narrow( baseGroup );
5539
5540   pyDump << elemGroup << " = " << this << ".DoubleNodeElemGroupNew( "
5541          << theElems         << ", "
5542          << theNodesNot      << ", "
5543          << theAffectedElems << " )";
5544
5545   return elemGroup._retn();
5546 }
5547
5548 //================================================================================
5549 /*!
5550  * \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5551  * Works as DoubleNodeElemGroup(), but returns a new group with newly created elements.
5552  * \param theElems - group of of elements (edges or faces) to be replicated
5553  * \param theNodesNot - group of nodes not to replicated
5554  * \param theAffectedElems - group of elements to which the replicated nodes
5555  *        should be associated to.
5556  * \return a new group with newly created elements
5557  * \sa DoubleNodeElemGroup()
5558  */
5559 //================================================================================
5560
5561 SMESH::ListOfGroups*
5562 SMESH_MeshEditor_i::DoubleNodeElemGroup2New(SMESH::SMESH_GroupBase_ptr theElems,
5563                                             SMESH::SMESH_GroupBase_ptr theNodesNot,
5564                                             SMESH::SMESH_GroupBase_ptr theAffectedElems,
5565                                             CORBA::Boolean             theElemGroupNeeded,
5566                                             CORBA::Boolean             theNodeGroupNeeded)
5567   throw (SALOME::SALOME_Exception)
5568 {
5569   SMESH_TRY;
5570   SMESH::SMESH_Group_var aNewElemGroup, aNewNodeGroup;
5571   SMESH::ListOfGroups_var aTwoGroups = new SMESH::ListOfGroups();
5572   aTwoGroups->length( 2 );
5573
5574   if ( CORBA::is_nil( theElems ) && theElems->GetType() == SMESH::NODE )
5575     return aTwoGroups._retn();
5576
5577   initData();
5578
5579
5580   SMESHDS_Mesh* aMeshDS = getMeshDS();
5581   TIDSortedElemSet anElems, aNodes, anAffected;
5582   idSourceToSet( theElems, aMeshDS, anElems, SMDSAbs_All );
5583   idSourceToSet( theNodesNot, aMeshDS, aNodes, SMDSAbs_Node );
5584   idSourceToSet( theAffectedElems, aMeshDS, anAffected, SMDSAbs_All );
5585
5586
5587   bool aResult = getEditor().DoubleNodes( anElems, aNodes, anAffected );
5588
5589   declareMeshModified( /*isReComputeSafe=*/ !aResult );
5590
5591   TPythonDump pyDump;
5592
5593   if ( aResult )
5594   {
5595     // Create group with newly created elements
5596     CORBA::String_var elemGroupName = theElems->GetName();
5597     string aNewName = generateGroupName( string(elemGroupName.in()) + "_double");
5598     if ( !getEditor().GetLastCreatedElems().IsEmpty() && theElemGroupNeeded )
5599     {
5600       SMESH::long_array_var anIds = GetLastCreatedElems();
5601       SMESH::ElementType aGroupType = myMesh_i->GetElementType(anIds[0], true);
5602       aNewElemGroup = myMesh_i->CreateGroup(aGroupType, aNewName.c_str());
5603       aNewElemGroup->Add(anIds);
5604     }
5605     if ( !getEditor().GetLastCreatedNodes().IsEmpty() && theNodeGroupNeeded )
5606     {
5607       SMESH::long_array_var anIds = GetLastCreatedNodes();
5608       aNewNodeGroup = myMesh_i->CreateGroup(SMESH::NODE, aNewName.c_str());
5609       aNewNodeGroup->Add(anIds);
5610     }
5611   }
5612
5613   // Update Python script
5614
5615   pyDump << "[ ";
5616   if ( aNewElemGroup->_is_nil() ) pyDump << "nothing, ";
5617   else                            pyDump << aNewElemGroup << ", ";
5618   if ( aNewNodeGroup->_is_nil() ) pyDump << "nothing ] = ";
5619   else                            pyDump << aNewNodeGroup << " ] = ";
5620
5621   pyDump << this << ".DoubleNodeElemGroup2New( " << theElems << ", "
5622          << theNodesNot        << ", "
5623          << theAffectedElems   << ", "
5624          << theElemGroupNeeded << ", "
5625          << theNodeGroupNeeded <<" )";
5626
5627   aTwoGroups[0] = aNewElemGroup._retn();
5628   aTwoGroups[1] = aNewNodeGroup._retn();
5629   return aTwoGroups._retn();
5630
5631   SMESH_CATCH( SMESH::throwCorbaException );
5632   return 0;
5633 }
5634
5635 //================================================================================
5636 /*!
5637   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5638   \param theElems - group of of elements (edges or faces) to be replicated
5639   \param theNodesNot - group of nodes not to replicated
5640   \param theShape - shape to detect affected elements (element which geometric center
5641   located on or inside shape).
5642   The replicated nodes should be associated to affected elements.
5643   \return TRUE if operation has been completed successfully, FALSE otherwise
5644   \sa DoubleNodesInRegion(), DoubleNodeGroupsInRegion()
5645 */
5646 //================================================================================
5647
5648 CORBA::Boolean
5649 SMESH_MeshEditor_i::DoubleNodeElemGroupInRegion(SMESH::SMESH_GroupBase_ptr theElems,
5650                                                 SMESH::SMESH_GroupBase_ptr theNodesNot,
5651                                                 GEOM::GEOM_Object_ptr      theShape )
5652   throw (SALOME::SALOME_Exception)
5653 {
5654   SMESH_TRY;
5655   if ( CORBA::is_nil( theElems ) && theElems->GetType() == SMESH::NODE )
5656     return false;
5657
5658   initData();
5659
5660
5661   SMESHDS_Mesh* aMeshDS = getMeshDS();
5662   TIDSortedElemSet anElems, aNodes, anAffected;
5663   idSourceToSet( theElems, aMeshDS, anElems, SMDSAbs_All );
5664   idSourceToSet( theNodesNot, aMeshDS, aNodes, SMDSAbs_Node );
5665
5666   TopoDS_Shape aShape = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape( theShape );
5667   bool aResult = getEditor().DoubleNodesInRegion( anElems, aNodes, aShape );
5668
5669
5670   declareMeshModified( /*isReComputeSafe=*/ !aResult );
5671
5672   // Update Python script
5673   TPythonDump() << "isDone = " << this << ".DoubleNodeElemGroupInRegion( " << theElems << ", "
5674                 << theNodesNot << ", " << theShape << " )";
5675   return aResult;
5676
5677   SMESH_CATCH( SMESH::throwCorbaException );
5678   return 0;
5679 }
5680
5681 //================================================================================
5682 /*!
5683  * \brief Re-load elements from a list of groups into a TIDSortedElemSet
5684  *  \param [in] theGrpList - groups
5685  *  \param [in] theMeshDS -  mesh
5686  *  \param [out] theElemSet - set of elements
5687  *  \param [in] theIsNodeGrp - is \a theGrpList includes goups of nodes
5688  */
5689 //================================================================================
5690
5691 static void listOfGroupToSet(const SMESH::ListOfGroups& theGrpList,
5692                              SMESHDS_Mesh*              theMeshDS,
5693                              TIDSortedElemSet&          theElemSet,
5694                              const bool                 theIsNodeGrp)
5695 {
5696   for ( int i = 0, n = theGrpList.length(); i < n; i++ )
5697   {
5698     SMESH::SMESH_GroupBase_var aGrp = theGrpList[ i ];
5699     if ( !CORBA::is_nil( aGrp ) && (theIsNodeGrp ? aGrp->GetType() == SMESH::NODE
5700                                     : aGrp->GetType() != SMESH::NODE ) )
5701     {
5702       SMESH::long_array_var anIDs = aGrp->GetIDs();
5703       arrayToSet( anIDs, theMeshDS, theElemSet, theIsNodeGrp ? SMDSAbs_Node : SMDSAbs_All );
5704     }
5705   }
5706 }
5707
5708 //================================================================================
5709 /*!
5710   \brief Creates a hole in a mesh by doubling the nodes of some particular elements.
5711   This method provided for convenience works as DoubleNodes() described above.
5712   \param theElems - list of groups of elements (edges or faces) to be replicated
5713   \param theNodesNot - list of groups of nodes not to replicated
5714   \param theAffectedElems - group of elements to which the replicated nodes
5715   should be associated to.
5716   \return TRUE if operation has been completed successfully, FALSE otherwise
5717   \sa DoubleNodeGroup(), DoubleNodes(), DoubleNodeElemGroupsNew()
5718 */
5719 //================================================================================
5720
5721 CORBA::Boolean
5722 SMESH_MeshEditor_i::DoubleNodeElemGroups(const SMESH::ListOfGroups& theElems,
5723                                          const SMESH::ListOfGroups& theNodesNot,
5724                                          const SMESH::ListOfGroups& theAffectedElems)
5725   throw (SALOME::SALOME_Exception)
5726 {
5727   SMESH_TRY;
5728   initData();
5729
5730
5731   SMESHDS_Mesh* aMeshDS = getMeshDS();
5732   TIDSortedElemSet anElems, aNodes, anAffected;
5733   listOfGroupToSet(theElems, aMeshDS, anElems, false );
5734   listOfGroupToSet(theNodesNot, aMeshDS, aNodes, true );
5735   listOfGroupToSet(theAffectedElems, aMeshDS, anAffected, false );
5736
5737   bool aResult = getEditor().DoubleNodes( anElems, aNodes, anAffected );
5738
5739   // Update Python script
5740   TPythonDump() << "isDone = " << this << ".DoubleNodeElemGroups( " << &theElems << ", "
5741                 << &theNodesNot << ", " << &theAffectedElems << " )";
5742
5743   declareMeshModified( /*isReComputeSafe=*/false );
5744   return aResult;
5745
5746   SMESH_CATCH( SMESH::throwCorbaException );
5747   return 0;
5748 }
5749
5750 //================================================================================
5751 /*!
5752  * \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5753  * Works as DoubleNodeElemGroups(), but returns a new group with newly created elements.
5754   \param theElems - list of groups of elements (edges or faces) to be replicated
5755   \param theNodesNot - list of groups of nodes not to replicated
5756   \param theAffectedElems - group of elements to which the replicated nodes
5757   should be associated to.
5758  * \return a new group with newly created elements
5759  * \sa DoubleNodeElemGroups()
5760  */
5761 //================================================================================
5762
5763 SMESH::SMESH_Group_ptr
5764 SMESH_MeshEditor_i::DoubleNodeElemGroupsNew(const SMESH::ListOfGroups& theElems,
5765                                             const SMESH::ListOfGroups& theNodesNot,
5766                                             const SMESH::ListOfGroups& theAffectedElems)
5767   throw (SALOME::SALOME_Exception)
5768 {
5769   TPythonDump pyDump;
5770   SMESH::ListOfGroups_var twoGroups = DoubleNodeElemGroups2New( theElems,
5771                                                                 theNodesNot,
5772                                                                 theAffectedElems,
5773                                                                 true, false );
5774   SMESH::SMESH_GroupBase_var baseGroup = twoGroups[0].in();
5775   SMESH::SMESH_Group_var     elemGroup = SMESH::SMESH_Group::_narrow( baseGroup );
5776
5777   pyDump << elemGroup << " = " << this << ".DoubleNodeElemGroupsNew( "
5778          << theElems         << ", "
5779          << theNodesNot      << ", "
5780          << theAffectedElems << " )";
5781
5782   return elemGroup._retn();
5783 }
5784
5785 //================================================================================
5786 /*!
5787  * \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5788  * Works as DoubleNodeElemGroups(), but returns a new group with newly created elements.
5789   \param theElems - list of groups of elements (edges or faces) to be replicated
5790   \param theNodesNot - list of groups of nodes not to replicated
5791   \param theAffectedElems - group of elements to which the replicated nodes
5792   should be associated to.
5793  * \return a new group with newly created elements
5794  * \sa DoubleNodeElemGroups()
5795  */
5796 //================================================================================
5797
5798 SMESH::ListOfGroups*
5799 SMESH_MeshEditor_i::DoubleNodeElemGroups2New(const SMESH::ListOfGroups& theElems,
5800                                              const SMESH::ListOfGroups& theNodesNot,
5801                                              const SMESH::ListOfGroups& theAffectedElems,
5802                                              CORBA::Boolean             theElemGroupNeeded,
5803                                              CORBA::Boolean             theNodeGroupNeeded)
5804   throw (SALOME::SALOME_Exception)
5805 {
5806   SMESH_TRY;
5807   SMESH::SMESH_Group_var aNewElemGroup, aNewNodeGroup;
5808   SMESH::ListOfGroups_var aTwoGroups = new SMESH::ListOfGroups();
5809   aTwoGroups->length( 2 );
5810   
5811   initData();
5812
5813
5814   SMESHDS_Mesh* aMeshDS = getMeshDS();
5815   TIDSortedElemSet anElems, aNodes, anAffected;
5816   listOfGroupToSet(theElems, aMeshDS, anElems, false );
5817   listOfGroupToSet(theNodesNot, aMeshDS, aNodes, true );
5818   listOfGroupToSet(theAffectedElems, aMeshDS, anAffected, false );
5819
5820   bool aResult = getEditor().DoubleNodes( anElems, aNodes, anAffected );
5821
5822   declareMeshModified( /*isReComputeSafe=*/ !aResult );
5823
5824   TPythonDump pyDump;
5825   if ( aResult )
5826   {
5827     // Create group with newly created elements
5828     CORBA::String_var elemGroupName = theElems[0]->GetName();
5829     string aNewName = generateGroupName( string(elemGroupName.in()) + "_double");
5830     if ( !getEditor().GetLastCreatedElems().IsEmpty() && theElemGroupNeeded )
5831     {
5832       SMESH::long_array_var anIds = GetLastCreatedElems();
5833       SMESH::ElementType aGroupType = myMesh_i->GetElementType(anIds[0], true);
5834       aNewElemGroup = myMesh_i->CreateGroup(aGroupType, aNewName.c_str());
5835       aNewElemGroup->Add(anIds);
5836     }
5837     if ( !getEditor().GetLastCreatedNodes().IsEmpty() && theNodeGroupNeeded )
5838     {
5839       SMESH::long_array_var anIds = GetLastCreatedNodes();
5840       aNewNodeGroup = myMesh_i->CreateGroup(SMESH::NODE, aNewName.c_str());
5841       aNewNodeGroup->Add(anIds);
5842     }
5843   }
5844
5845   // Update Python script
5846
5847   pyDump << "[ ";
5848   if ( aNewElemGroup->_is_nil() ) pyDump << "nothing, ";
5849   else                            pyDump << aNewElemGroup << ", ";
5850   if ( aNewNodeGroup->_is_nil() ) pyDump << "nothing ] = ";
5851   else                            pyDump << aNewNodeGroup << " ] = ";
5852
5853   pyDump << this << ".DoubleNodeElemGroups2New( " << &theElems << ", "
5854          << &theNodesNot       << ", "
5855          << &theAffectedElems  << ", "
5856          << theElemGroupNeeded << ", "
5857          << theNodeGroupNeeded << " )";
5858
5859   aTwoGroups[0] = aNewElemGroup._retn();
5860   aTwoGroups[1] = aNewNodeGroup._retn();
5861   return aTwoGroups._retn();
5862
5863   SMESH_CATCH( SMESH::throwCorbaException );
5864   return 0;
5865 }
5866
5867 //================================================================================
5868 /*!
5869   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5870   This method provided for convenience works as DoubleNodes() described above.
5871   \param theElems - list of groups of elements (edges or faces) to be replicated
5872   \param theNodesNot - list of groups of nodes not to replicated
5873   \param theShape - shape to detect affected elements (element which geometric center
5874   located on or inside shape).
5875   The replicated nodes should be associated to affected elements.
5876   \return TRUE if operation has been completed successfully, FALSE otherwise
5877   \sa DoubleNodeGroupInRegion(), DoubleNodesInRegion()
5878 */
5879 //================================================================================
5880
5881 CORBA::Boolean
5882 SMESH_MeshEditor_i::DoubleNodeElemGroupsInRegion(const SMESH::ListOfGroups& theElems,
5883                                                  const SMESH::ListOfGroups& theNodesNot,
5884                                                  GEOM::GEOM_Object_ptr      theShape )
5885   throw (SALOME::SALOME_Exception)
5886 {
5887   SMESH_TRY;
5888   initData();
5889
5890
5891   SMESHDS_Mesh* aMeshDS = getMeshDS();
5892   TIDSortedElemSet anElems, aNodes;
5893   listOfGroupToSet(theElems, aMeshDS, anElems,false );
5894   listOfGroupToSet(theNodesNot, aMeshDS, aNodes, true );
5895
5896   TopoDS_Shape aShape = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape( theShape );
5897   bool aResult = getEditor().DoubleNodesInRegion( anElems, aNodes, aShape );
5898
5899   // Update Python script
5900   TPythonDump() << "isDone = " << this << ".DoubleNodeElemGroupsInRegion( " << &theElems << ", "
5901                 << &theNodesNot << ", " << theShape << " )";
5902
5903   declareMeshModified( /*isReComputeSafe=*/ !aResult );
5904   return aResult;
5905
5906   SMESH_CATCH( SMESH::throwCorbaException );
5907   return 0;
5908 }
5909
5910 //================================================================================
5911 /*!
5912   \brief Identify the elements that will be affected by node duplication (actual
5913          duplication is not performed.
5914   This method is the first step of DoubleNodeElemGroupsInRegion.
5915   \param theElems - list of groups of elements (edges or faces) to be replicated
5916   \param theNodesNot - list of groups of nodes not to replicated
5917   \param theShape - shape to detect affected elements (element which geometric center
5918          located on or inside shape).
5919          The replicated nodes should be associated to affected elements.
5920   \return groups of affected elements
5921   \sa DoubleNodeElemGroupsInRegion()
5922 */
5923 //================================================================================
5924 SMESH::ListOfGroups*
5925 SMESH_MeshEditor_i::AffectedElemGroupsInRegion( const SMESH::ListOfGroups& theElems,
5926                                                 const SMESH::ListOfGroups& theNodesNot,
5927                                                 GEOM::GEOM_Object_ptr      theShape )
5928   throw (SALOME::SALOME_Exception)
5929 {
5930   SMESH_TRY;
5931   MESSAGE("AffectedElemGroupsInRegion");
5932   SMESH::ListOfGroups_var aListOfGroups = new SMESH::ListOfGroups();
5933   bool isEdgeGroup = false;
5934   bool isFaceGroup = false;
5935   bool isVolumeGroup = false;
5936   SMESH::SMESH_Group_var aNewEdgeGroup = myMesh_i->CreateGroup(SMESH::EDGE, "affectedEdges");
5937   SMESH::SMESH_Group_var aNewFaceGroup = myMesh_i->CreateGroup(SMESH::FACE, "affectedFaces");
5938   SMESH::SMESH_Group_var aNewVolumeGroup = myMesh_i->CreateGroup(SMESH::VOLUME, "affectedVolumes");
5939
5940   initData();
5941
5942   ::SMESH_MeshEditor aMeshEditor(myMesh);
5943
5944   SMESHDS_Mesh* aMeshDS = getMeshDS();
5945   TIDSortedElemSet anElems, aNodes;
5946   listOfGroupToSet(theElems, aMeshDS, anElems, false);
5947   listOfGroupToSet(theNodesNot, aMeshDS, aNodes, true);
5948
5949   TopoDS_Shape aShape = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape(theShape);
5950   TIDSortedElemSet anAffected;
5951   bool aResult = aMeshEditor.AffectedElemGroupsInRegion(anElems, aNodes, aShape, anAffected);
5952
5953
5954   declareMeshModified( /*isReComputeSafe=*/ !aResult );
5955
5956   TPythonDump pyDump;
5957   if (aResult)
5958   {
5959     int lg = anAffected.size();
5960     MESSAGE("lg="<< lg);
5961     SMESH::long_array_var volumeIds = new SMESH::long_array;
5962     volumeIds->length(lg);
5963     SMESH::long_array_var faceIds = new SMESH::long_array;
5964     faceIds->length(lg);
5965     SMESH::long_array_var edgeIds = new SMESH::long_array;
5966     edgeIds->length(lg);
5967     int ivol = 0;
5968     int iface = 0;
5969     int iedge = 0;
5970
5971     TIDSortedElemSet::const_iterator eIt = anAffected.begin();
5972     for (; eIt != anAffected.end(); ++eIt)
5973     {
5974       const SMDS_MeshElement* anElem = *eIt;
5975       if (!anElem)
5976         continue;
5977       int elemId = anElem->GetID();
5978       if (myMesh->GetElementType(elemId, true) == SMDSAbs_Volume)
5979         volumeIds[ivol++] = elemId;
5980       else if (myMesh->GetElementType(elemId, true) == SMDSAbs_Face)
5981         faceIds[iface++] = elemId;
5982       else if (myMesh->GetElementType(elemId, true) == SMDSAbs_Edge)
5983         edgeIds[iedge++] = elemId;
5984     }
5985     volumeIds->length(ivol);
5986     faceIds->length(iface);
5987     edgeIds->length(iedge);
5988
5989     aNewVolumeGroup->Add(volumeIds);
5990     aNewFaceGroup->Add(faceIds);
5991     aNewEdgeGroup->Add(edgeIds);
5992     isVolumeGroup = (aNewVolumeGroup->Size() > 0);
5993     isFaceGroup = (aNewFaceGroup->Size() > 0);
5994     isEdgeGroup = (aNewEdgeGroup->Size() > 0);
5995   }
5996
5997   int nbGroups = 0;
5998   if (isEdgeGroup)   nbGroups++;
5999   if (isFaceGroup)   nbGroups++;
6000   if (isVolumeGroup) nbGroups++;
6001   aListOfGroups->length(nbGroups);
6002
6003   int i = 0;
6004   if (isEdgeGroup)   aListOfGroups[i++] = aNewEdgeGroup._retn();
6005   if (isFaceGroup)   aListOfGroups[i++] = aNewFaceGroup._retn();
6006   if (isVolumeGroup) aListOfGroups[i++] = aNewVolumeGroup._retn();
6007
6008   // Update Python script
6009
6010   pyDump << "[ ";
6011   if (isEdgeGroup)   pyDump << aNewEdgeGroup << ", ";
6012   if (isFaceGroup)   pyDump << aNewFaceGroup << ", ";
6013   if (isVolumeGroup) pyDump << aNewVolumeGroup << ", ";
6014   pyDump << "] = ";
6015   pyDump << this << ".AffectedElemGroupsInRegion( "
6016          << &theElems << ", " << &theNodesNot << ", " << theShape << " )";
6017
6018   return aListOfGroups._retn();
6019
6020   SMESH_CATCH( SMESH::throwCorbaException );
6021   return 0;
6022 }
6023
6024 //================================================================================
6025 /*!
6026   \brief Generated skin mesh (containing 2D cells) from 3D mesh
6027    The created 2D mesh elements based on nodes of free faces of boundary volumes
6028   \return TRUE if operation has been completed successfully, FALSE otherwise
6029 */
6030 //================================================================================
6031
6032 CORBA::Boolean SMESH_MeshEditor_i::Make2DMeshFrom3D()
6033   throw (SALOME::SALOME_Exception)
6034 {
6035   SMESH_TRY;
6036   initData();
6037
6038   bool aResult = getEditor().Make2DMeshFrom3D();
6039
6040   TPythonDump() << "isDone = " << this << ".Make2DMeshFrom3D()";
6041
6042   declareMeshModified( /*isReComputeSafe=*/ !aResult );
6043   return aResult;
6044
6045   SMESH_CATCH( SMESH::throwCorbaException );
6046   return false;
6047 }
6048
6049 //================================================================================
6050 /*!
6051  * \brief Double nodes on shared faces between groups of volumes and create flat elements on demand.
6052  * The list of groups must contain at least two groups. The groups have to be disjoint:
6053  * no common element into two different groups.
6054  * The nodes of the internal faces at the boundaries of the groups are doubled.
6055  * Optionally, the internal faces are replaced by flat elements.
6056  * Triangles are transformed into prisms, and quadrangles into hexahedrons.
6057  * The flat elements are stored in groups of volumes.
6058  * These groups are named according to the position of the group in the list:
6059  * 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.
6060  * 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.
6061  * All the flat elements are gathered into the group named "joints3D" (or "joints2D" in 2D situation).
6062  * The flat element of the multiple junctions between the simple junction are stored in a group named "jointsMultiples".
6063  * \param theDomains - list of groups of volumes
6064  * \param createJointElems - if TRUE, create the elements
6065  * \param onAllBoundaries - if TRUE, the nodes and elements are also created on
6066  *        the boundary between \a theDomains and the rest mesh
6067  * \return TRUE if operation has been completed successfully, FALSE otherwise
6068  */
6069 //================================================================================
6070
6071 CORBA::Boolean
6072 SMESH_MeshEditor_i::DoubleNodesOnGroupBoundaries( const SMESH::ListOfGroups& theDomains,
6073                                                   CORBA::Boolean             createJointElems,
6074                                                   CORBA::Boolean             onAllBoundaries )
6075   throw (SALOME::SALOME_Exception)
6076 {
6077   bool isOK = false;
6078
6079   SMESH_TRY;
6080   initData();
6081
6082   SMESHDS_Mesh* aMeshDS = getMeshDS();
6083
6084   // MESSAGE("theDomains.length = "<<theDomains.length());
6085   if ( theDomains.length() <= 1 && !onAllBoundaries )
6086     THROW_SALOME_CORBA_EXCEPTION("At least 2 groups are required.", SALOME::BAD_PARAM);
6087
6088   vector<TIDSortedElemSet> domains;
6089   domains.resize( theDomains.length() );
6090
6091   for ( int i = 0, n = theDomains.length(); i < n; i++ )
6092   {
6093     SMESH::SMESH_GroupBase_var aGrp = theDomains[ i ];
6094     if ( !CORBA::is_nil( aGrp ) /*&& ( aGrp->GetType() != SMESH::NODE )*/ )
6095     {
6096 //      if ( aGrp->GetType() != SMESH::VOLUME )
6097 //        THROW_SALOME_CORBA_EXCEPTION("Not a volume group", SALOME::BAD_PARAM);
6098       SMESH::long_array_var anIDs = aGrp->GetIDs();
6099       arrayToSet( anIDs, aMeshDS, domains[ i ], SMDSAbs_All );
6100     }
6101   }
6102
6103   isOK = getEditor().DoubleNodesOnGroupBoundaries( domains, createJointElems, onAllBoundaries );
6104   // TODO publish the groups of flat elements in study
6105
6106   declareMeshModified( /*isReComputeSafe=*/ !isOK );
6107
6108   // Update Python script
6109   TPythonDump() << "isDone = " << this << ".DoubleNodesOnGroupBoundaries( " << &theDomains
6110                 << ", " << createJointElems << ", " << onAllBoundaries << " )";
6111
6112   SMESH_CATCH( SMESH::throwCorbaException );
6113
6114   myMesh_i->CreateGroupServants(); // publish created groups if any
6115
6116   return isOK;
6117 }
6118
6119 //================================================================================
6120 /*!
6121  * \brief Double nodes on some external faces and create flat elements.
6122  * Flat elements are mainly used by some types of mechanic calculations.
6123  *
6124  * Each group of the list must be constituted of faces.
6125  * Triangles are transformed in prisms, and quadrangles in hexahedrons.
6126  * @param theGroupsOfFaces - list of groups of faces
6127  * @return TRUE if operation has been completed successfully, FALSE otherwise
6128  */
6129 //================================================================================
6130
6131 CORBA::Boolean
6132 SMESH_MeshEditor_i::CreateFlatElementsOnFacesGroups( const SMESH::ListOfGroups& theGroupsOfFaces )
6133   throw (SALOME::SALOME_Exception)
6134 {
6135   SMESH_TRY;
6136   initData();
6137
6138   SMESHDS_Mesh* aMeshDS = getMeshDS();
6139
6140   vector<TIDSortedElemSet> faceGroups;
6141   faceGroups.clear();
6142
6143   for ( int i = 0, n = theGroupsOfFaces.length(); i < n; i++ )
6144   {
6145     SMESH::SMESH_GroupBase_var aGrp = theGroupsOfFaces[ i ];
6146     if ( !CORBA::is_nil( aGrp ) && ( aGrp->GetType() != SMESH::NODE ) )
6147     {
6148       TIDSortedElemSet faceGroup;
6149       faceGroup.clear();
6150       faceGroups.push_back(faceGroup);
6151       SMESH::long_array_var anIDs = aGrp->GetIDs();
6152       arrayToSet( anIDs, aMeshDS, faceGroups[ i ], SMDSAbs_All );
6153     }
6154   }
6155
6156   bool aResult = getEditor().CreateFlatElementsOnFacesGroups( faceGroups );
6157   // TODO publish the groups of flat elements in study
6158
6159   declareMeshModified( /*isReComputeSafe=*/ !aResult );
6160
6161   // Update Python script
6162   TPythonDump() << this << ".CreateFlatElementsOnFacesGroups( " << &theGroupsOfFaces << " )";
6163   return aResult;
6164
6165   SMESH_CATCH( SMESH::throwCorbaException );
6166   return false;
6167 }
6168
6169 //================================================================================
6170 /*!
6171  *  \brief Identify all the elements around a geom shape, get the faces delimiting
6172  *         the hole.
6173  *
6174  *  Build groups of volume to remove, groups of faces to replace on the skin of the
6175  *  object, groups of faces to remove inside the object, (idem edges).
6176  *  Build ordered list of nodes at the border of each group of faces to replace
6177  *  (to be used to build a geom subshape).
6178  */
6179 //================================================================================
6180
6181 void SMESH_MeshEditor_i::CreateHoleSkin(CORBA::Double                  radius,
6182                                         GEOM::GEOM_Object_ptr          theShape,
6183                                         const char*                    groupName,
6184                                         const SMESH::double_array&     theNodesCoords,
6185                                         SMESH::array_of_long_array_out GroupsOfNodes)
6186   throw (SALOME::SALOME_Exception)
6187 {
6188   SMESH_TRY;
6189
6190   initData();
6191   std::vector<std::vector<int> > aListOfListOfNodes;
6192   ::SMESH_MeshEditor aMeshEditor( myMesh );
6193
6194   theSearchersDeleter.Set( myMesh ); // remove theNodeSearcher if mesh is other
6195   if ( !theNodeSearcher )
6196     theNodeSearcher = SMESH_MeshAlgos::GetNodeSearcher( *getMeshDS() );
6197
6198   vector<double> nodesCoords;
6199   for (int i = 0; i < theNodesCoords.length(); i++)
6200   {
6201     nodesCoords.push_back( theNodesCoords[i] );
6202   }
6203
6204   TopoDS_Shape aShape = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape( theShape );
6205   aMeshEditor.CreateHoleSkin(radius, aShape, theNodeSearcher, groupName,
6206                              nodesCoords, aListOfListOfNodes);
6207
6208   GroupsOfNodes = new SMESH::array_of_long_array;
6209   GroupsOfNodes->length( aListOfListOfNodes.size() );
6210   std::vector<std::vector<int> >::iterator llIt = aListOfListOfNodes.begin();
6211   for ( CORBA::Long i = 0; llIt != aListOfListOfNodes.end(); llIt++, i++ )
6212   {
6213     vector<int>& aListOfNodes = *llIt;
6214     vector<int>::iterator lIt = aListOfNodes.begin();;
6215     SMESH::long_array& aGroup = (*GroupsOfNodes)[ i ];
6216     aGroup.length( aListOfNodes.size() );
6217     for ( int j = 0; lIt != aListOfNodes.end(); lIt++, j++ )
6218       aGroup[ j ] = (*lIt);
6219   }
6220   TPythonDump() << "lists_nodes = " << this << ".CreateHoleSkin( "
6221                 << radius << ", "
6222                 << theShape
6223                 << ", '" << groupName << "', "
6224                 << theNodesCoords << " )";
6225
6226   SMESH_CATCH( SMESH::throwCorbaException );
6227 }
6228
6229 // issue 20749 ===================================================================
6230 /*!
6231  * \brief Creates missing boundary elements
6232  *  \param elements - elements whose boundary is to be checked
6233  *  \param dimension - defines type of boundary elements to create
6234  *  \param groupName - a name of group to store created boundary elements in,
6235  *                     "" means not to create the group
6236  *  \param meshName - a name of new mesh to store created boundary elements in,
6237  *                     "" means not to create the new mesh
6238  *  \param toCopyElements - if true, the checked elements will be copied into the new mesh
6239  *  \param toCopyExistingBondary - if true, not only new but also pre-existing
6240  *                                boundary elements will be copied into the new mesh
6241  *  \param group - returns the create group, if any
6242  *  \retval SMESH::SMESH_Mesh - the mesh where elements were added to
6243  */
6244 // ================================================================================
6245
6246 SMESH::SMESH_Mesh_ptr
6247 SMESH_MeshEditor_i::MakeBoundaryMesh(SMESH::SMESH_IDSource_ptr idSource,
6248                                      SMESH::Bnd_Dimension      dim,
6249                                      const char*               groupName,
6250                                      const char*               meshName,
6251                                      CORBA::Boolean            toCopyElements,
6252                                      CORBA::Boolean            toCopyExistingBondary,
6253                                      SMESH::SMESH_Group_out    group)
6254   throw (SALOME::SALOME_Exception)
6255 {
6256   SMESH_TRY;
6257   initData();
6258
6259   if ( dim > SMESH::BND_1DFROM2D )
6260     THROW_SALOME_CORBA_EXCEPTION("Invalid boundary dimension", SALOME::BAD_PARAM);
6261
6262   SMESHDS_Mesh* aMeshDS = getMeshDS();
6263
6264   SMESH::SMESH_Mesh_var mesh_var;
6265   SMESH::SMESH_Group_var group_var;
6266
6267   TPythonDump pyDump;
6268
6269   TIDSortedElemSet elements;
6270   SMDSAbs_ElementType elemType = (dim == SMESH::BND_1DFROM2D) ? SMDSAbs_Face : SMDSAbs_Volume;
6271   if ( idSourceToSet( idSource, aMeshDS, elements, elemType,/*emptyIfIsMesh=*/true ))
6272   {
6273     // mesh to fill in
6274     mesh_var =
6275       strlen(meshName) ? makeMesh(meshName) : SMESH::SMESH_Mesh::_duplicate(myMesh_i->_this());
6276     SMESH_Mesh_i* mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh_var );
6277     // other mesh
6278     SMESH_Mesh* smesh_mesh = (mesh_i==myMesh_i) ? (SMESH_Mesh*)0 : &mesh_i->GetImpl();
6279
6280     // group of new boundary elements
6281     SMESH_Group* smesh_group = 0;
6282     if ( strlen(groupName) )
6283     {
6284       group_var = mesh_i->CreateGroup( SMESH::ElementType(int(elemType)-1),groupName);
6285       if ( SMESH_GroupBase_i* group_i = SMESH::DownCast<SMESH_GroupBase_i*>( group_var ))
6286         smesh_group = group_i->GetSmeshGroup();
6287     }
6288
6289     // do it
6290     getEditor().MakeBoundaryMesh( elements,
6291                                   ::SMESH_MeshEditor::Bnd_Dimension(dim),
6292                                   smesh_group,
6293                                   smesh_mesh,
6294                                   toCopyElements,
6295                                   toCopyExistingBondary);
6296
6297     if ( smesh_mesh )
6298       smesh_mesh->GetMeshDS()->Modified();
6299   }
6300
6301   const char* dimName[] = { "BND_2DFROM3D", "BND_1DFROM3D", "BND_1DFROM2D" };
6302
6303   // result of MakeBoundaryMesh() is a tuple (mesh, group)
6304   if ( mesh_var->_is_nil() )
6305     pyDump << myMesh_i->_this() << ", ";
6306   else
6307     pyDump << mesh_var << ", ";
6308   if ( group_var->_is_nil() )
6309     pyDump << "_NoneGroup = "; // assignment to None is forbiden
6310   else
6311     pyDump << group_var << " = ";
6312   pyDump << this << ".MakeBoundaryMesh( "
6313          << idSource << ", "
6314          << "SMESH." << dimName[int(dim)] << ", "
6315          << "'" << groupName << "', "
6316          << "'" << meshName<< "', "
6317          << toCopyElements << ", "
6318          << toCopyExistingBondary << ")";
6319
6320   group = group_var._retn();
6321   return mesh_var._retn();
6322
6323   SMESH_CATCH( SMESH::throwCorbaException );
6324   return SMESH::SMESH_Mesh::_nil();
6325 }
6326
6327 //================================================================================
6328 /*!
6329  * \brief Creates missing boundary elements
6330  *  \param dimension - defines type of boundary elements to create
6331  *  \param groupName - a name of group to store all boundary elements in,
6332  *    "" means not to create the group
6333  *  \param meshName - a name of a new mesh, which is a copy of the initial 
6334  *    mesh + created boundary elements; "" means not to create the new mesh
6335  *  \param toCopyAll - if true, the whole initial mesh will be copied into
6336  *    the new mesh else only boundary elements will be copied into the new mesh
6337  *  \param groups - optional groups of elements to make boundary around
6338  *  \param mesh - returns the mesh where elements were added to
6339  *  \param group - returns the created group, if any
6340  *  \retval long - number of added boundary elements
6341  */
6342 //================================================================================
6343
6344 CORBA::Long SMESH_MeshEditor_i::MakeBoundaryElements(SMESH::Bnd_Dimension dim,
6345                                                      const char* groupName,
6346                                                      const char* meshName,
6347                                                      CORBA::Boolean toCopyAll,
6348                                                      const SMESH::ListOfIDSources& groups,
6349                                                      SMESH::SMESH_Mesh_out mesh,
6350                                                      SMESH::SMESH_Group_out group)
6351   throw (SALOME::SALOME_Exception)
6352 {
6353   SMESH_TRY;
6354   initData();
6355
6356   if ( dim > SMESH::BND_1DFROM2D )
6357     THROW_SALOME_CORBA_EXCEPTION("Invalid boundary dimension", SALOME::BAD_PARAM);
6358
6359   // separate groups belonging to this and other mesh
6360   SMESH::ListOfIDSources_var groupsOfThisMesh = new SMESH::ListOfIDSources;
6361   SMESH::ListOfIDSources_var groupsOfOtherMesh = new SMESH::ListOfIDSources;
6362   groupsOfThisMesh->length( groups.length() );
6363   groupsOfOtherMesh->length( groups.length() );
6364   int nbGroups = 0, nbGroupsOfOtherMesh = 0;
6365   for ( int i = 0; i < groups.length(); ++i )
6366   {
6367     SMESH::SMESH_Mesh_var m = groups[i]->GetMesh();
6368     if ( myMesh_i != SMESH::DownCast<SMESH_Mesh_i*>( m ))
6369       groupsOfOtherMesh[ nbGroupsOfOtherMesh++ ] = groups[i];
6370     else
6371       groupsOfThisMesh[ nbGroups++ ] = groups[i];
6372     if ( SMESH::DownCast<SMESH_Mesh_i*>( groups[i] ))
6373       THROW_SALOME_CORBA_EXCEPTION("expect a group but recieve a mesh", SALOME::BAD_PARAM);
6374   }
6375   groupsOfThisMesh->length( nbGroups );
6376   groupsOfOtherMesh->length( nbGroupsOfOtherMesh );
6377
6378   int nbAdded = 0;
6379   TPythonDump pyDump;
6380
6381   if ( nbGroupsOfOtherMesh > 0 )
6382   {
6383     // process groups belonging to another mesh
6384     SMESH::SMESH_Mesh_var    otherMesh = groupsOfOtherMesh[0]->GetMesh();
6385     SMESH::SMESH_MeshEditor_var editor = otherMesh->GetMeshEditor();
6386     nbAdded += editor->MakeBoundaryElements( dim, groupName, meshName, toCopyAll,
6387                                              groupsOfOtherMesh, mesh, group );
6388   }
6389
6390   SMESH::SMESH_Mesh_var mesh_var;
6391   SMESH::SMESH_Group_var group_var;
6392
6393   // get mesh to fill
6394   mesh_var = SMESH::SMESH_Mesh::_duplicate( myMesh_i->_this() );
6395   const bool toCopyMesh = ( strlen( meshName ) > 0 );
6396   if ( toCopyMesh )
6397   {
6398     if ( toCopyAll )
6399       mesh_var = SMESH_Gen_i::GetSMESHGen()->CopyMesh(mesh_var,
6400                                                       meshName,
6401                                                       /*toCopyGroups=*/false,
6402                                                       /*toKeepIDs=*/true);
6403     else
6404       mesh_var = makeMesh(meshName);
6405   }
6406   SMESH_Mesh_i* mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh_var );
6407   SMESH_Mesh*  tgtMesh = &mesh_i->GetImpl();
6408
6409   // source mesh
6410   SMESH_Mesh*     srcMesh = ( toCopyMesh && !toCopyAll ) ? myMesh : tgtMesh;
6411   SMESHDS_Mesh* srcMeshDS = srcMesh->GetMeshDS();
6412
6413   // group of boundary elements
6414   SMESH_Group* smesh_group = 0;
6415   SMDSAbs_ElementType elemType = (dim == SMESH::BND_2DFROM3D) ? SMDSAbs_Volume : SMDSAbs_Face;
6416   if ( strlen(groupName) )
6417   {
6418     SMESH::ElementType groupType = SMESH::ElementType( int(elemType)-1 );
6419     group_var = mesh_i->CreateGroup( groupType, groupName );
6420     if ( SMESH_GroupBase_i* group_i = SMESH::DownCast<SMESH_GroupBase_i*>( group_var ))
6421       smesh_group = group_i->GetSmeshGroup();
6422   }
6423
6424   TIDSortedElemSet elements;
6425
6426   if ( groups.length() > 0 )
6427   {
6428     for ( int i = 0; i < nbGroups; ++i )
6429     {
6430       elements.clear();
6431       if ( idSourceToSet( groupsOfThisMesh[i], srcMeshDS, elements, elemType,/*emptyIfIsMesh=*/0 ))
6432       {
6433         SMESH::Bnd_Dimension bdim = 
6434           ( elemType == SMDSAbs_Volume ) ? SMESH::BND_2DFROM3D : SMESH::BND_1DFROM2D;
6435         nbAdded += getEditor().MakeBoundaryMesh( elements,
6436                                                  ::SMESH_MeshEditor::Bnd_Dimension(bdim),
6437                                                  smesh_group,
6438                                                  tgtMesh,
6439                                                  /*toCopyElements=*/false,
6440                                                  /*toCopyExistingBondary=*/srcMesh != tgtMesh,
6441                                                  /*toAddExistingBondary=*/true,
6442                                                  /*aroundElements=*/true);
6443       }
6444     }
6445   }
6446   else
6447   {
6448     nbAdded += getEditor().MakeBoundaryMesh( elements,
6449                                              ::SMESH_MeshEditor::Bnd_Dimension(dim),
6450                                              smesh_group,
6451                                              tgtMesh,
6452                                              /*toCopyElements=*/false,
6453                                              /*toCopyExistingBondary=*/srcMesh != tgtMesh,
6454                                              /*toAddExistingBondary=*/true);
6455   }
6456   tgtMesh->GetMeshDS()->Modified();
6457
6458   const char* dimName[] = { "BND_2DFROM3D", "BND_1DFROM3D", "BND_1DFROM2D" };
6459
6460   // result of MakeBoundaryElements() is a tuple (nb, mesh, group)
6461   pyDump << "nbAdded, ";
6462   if ( mesh_var->_is_nil() )
6463     pyDump << myMesh_i->_this() << ", ";
6464   else
6465     pyDump << mesh_var << ", ";
6466   if ( group_var->_is_nil() )
6467     pyDump << "_NoneGroup = "; // assignment to None is forbiden
6468   else
6469     pyDump << group_var << " = ";
6470   pyDump << this << ".MakeBoundaryElements( "
6471          << "SMESH." << dimName[int(dim)] << ", "
6472          << "'" << groupName << "', "
6473          << "'" << meshName<< "', "
6474          << toCopyAll << ", "
6475          << groups << ")";
6476
6477   mesh  = mesh_var._retn();
6478   group = group_var._retn();
6479   return nbAdded;
6480
6481   SMESH_CATCH( SMESH::throwCorbaException );
6482   return 0;
6483 }