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