Salome HOME
Merge branch 'abn/configuration'
[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 LinearVariation = false,
2488                           CORBA::Boolean ByAverageNormal = false,
2489                           CORBA::Boolean UseInputElemsOnly = false,
2490                           CORBA::Long    Flags = 0,
2491                           CORBA::Boolean MakeBoundary = true )
2492     {
2493       if ( MakeGroups       ) Flags |= ::SMESH_MeshEditor::EXTRUSION_FLAG_GROUPS;
2494       if ( ByAverageNormal  ) Flags |= ::SMESH_MeshEditor::EXTRUSION_FLAG_BY_AVG_NORMAL;
2495       if ( UseInputElemsOnly) Flags |= ::SMESH_MeshEditor::EXTRUSION_FLAG_USE_INPUT_ELEMS_ONLY;
2496       if ( LinearVariation  ) Flags |= ::SMESH_MeshEditor::EXTRUSION_FLAG_SCALE_LINEAR_VARIATION;
2497       if ( MakeBoundary     ) Flags |= ::SMESH_MeshEditor::EXTRUSION_FLAG_BOUNDARY;
2498       return Flags;
2499     }
2500     // standard params
2501     ExtrusionParams(const SMESH::DirStruct &    theDir,
2502                     CORBA::Long                 theNbOfSteps,
2503                     const SMESH::double_array & theScaleFactors,
2504                     CORBA::Boolean              theLinearVariation,
2505                     const SMESH::double_array & theBasePoint,
2506                     CORBA::Boolean              theMakeGroups):
2507       ::SMESH_MeshEditor::ExtrusParam ( gp_Vec( theDir.PS.x,
2508                                                 theDir.PS.y,
2509                                                 theDir.PS.z ),
2510                                         theNbOfSteps,
2511                                         toList( theScaleFactors ),
2512                                         TBasePoint( theBasePoint ),
2513                                         makeFlags( theMakeGroups, theLinearVariation )),
2514       myIsExtrusionByNormal( false )
2515     {
2516     }
2517     // advanced params
2518     ExtrusionParams(const SMESH::DirStruct &  theDir,
2519                     CORBA::Long               theNbOfSteps,
2520                     CORBA::Boolean            theMakeGroups,
2521                     CORBA::Long               theExtrFlags,
2522                     CORBA::Double             theSewTolerance):
2523       ::SMESH_MeshEditor::ExtrusParam ( gp_Vec( theDir.PS.x,
2524                                                 theDir.PS.y,
2525                                                 theDir.PS.z ),
2526                                         theNbOfSteps,
2527                                         std::list<double>(),
2528                                         0,
2529                                         makeFlags( theMakeGroups, false, false, false,
2530                                                    theExtrFlags, false ),
2531                                         theSewTolerance ),
2532       myIsExtrusionByNormal( false )
2533     {
2534     }
2535     // params for extrusion by normal
2536     ExtrusionParams(CORBA::Double  theStepSize,
2537                     CORBA::Long    theNbOfSteps,
2538                     CORBA::Short   theDim,
2539                     CORBA::Boolean theByAverageNormal,
2540                     CORBA::Boolean theUseInputElemsOnly,
2541                     CORBA::Boolean theMakeGroups ):
2542       ::SMESH_MeshEditor::ExtrusParam ( theStepSize, 
2543                                         theNbOfSteps,
2544                                         makeFlags( theMakeGroups, false,
2545                                                    theByAverageNormal, theUseInputElemsOnly ),
2546                                         theDim),
2547       myIsExtrusionByNormal( true )
2548     {
2549     }
2550
2551     void SetNoGroups()
2552     {
2553       Flags() &= ~(::SMESH_MeshEditor::EXTRUSION_FLAG_GROUPS);
2554     }
2555
2556   private:
2557
2558     static std::list<double> toList( const SMESH::double_array & theScaleFactors )
2559     {
2560       std::list<double> scales;
2561       for ( CORBA::ULong i = 0; i < theScaleFactors.length(); ++i )
2562         scales.push_back( theScaleFactors[i] );
2563       return scales;
2564     }
2565
2566     // structure used to convert SMESH::double_array to gp_XYZ*
2567     struct TBasePoint
2568     {
2569       gp_XYZ *pp, p;
2570       TBasePoint( const SMESH::double_array & theBasePoint )
2571       {
2572         pp = 0;
2573         if ( theBasePoint.length() == 3 )
2574         {
2575           p.SetCoord( theBasePoint[0], theBasePoint[1], theBasePoint[2] );
2576           pp = &p;
2577         }
2578       }
2579       operator const gp_XYZ*() const { return pp; }
2580     };
2581   };
2582 }
2583
2584 //=======================================================================
2585 /*!
2586  * \brief Generate dim+1 elements by extrusion of elements along vector
2587  *  \param [in] edges - edges to extrude: a list including groups, sub-meshes or a mesh
2588  *  \param [in] faces - faces to extrude: a list including groups, sub-meshes or a mesh
2589  *  \param [in] nodes - nodes to extrude: a list including groups, sub-meshes or a mesh
2590  *  \param [in] stepVector - vector giving direction and distance of an extrusion step
2591  *  \param [in] nbOfSteps - number of elements to generate from one element
2592  *  \param [in] toMakeGroups - if true, new elements will be included into new groups
2593  *              corresponding to groups the input elements included in.
2594  *  \return ListOfGroups - new groups craeted if \a toMakeGroups is true
2595  */
2596 //=======================================================================
2597
2598 SMESH::ListOfGroups*
2599 SMESH_MeshEditor_i::ExtrusionSweepObjects(const SMESH::ListOfIDSources & theNodes,
2600                                           const SMESH::ListOfIDSources & theEdges,
2601                                           const SMESH::ListOfIDSources & theFaces,
2602                                           const SMESH::DirStruct &       theStepVector,
2603                                           CORBA::Long                    theNbOfSteps,
2604                                           const SMESH::double_array &    theScaleFactors,
2605                                           CORBA::Boolean                 theLinearVariation,
2606                                           const SMESH::double_array &    theBasePoint,
2607                                           CORBA::Boolean                 theToMakeGroups)
2608   throw (SALOME::SALOME_Exception)
2609 {
2610   SMESH_TRY;
2611   initData();
2612
2613   ExtrusionParams params( theStepVector, theNbOfSteps, theScaleFactors,
2614                           theLinearVariation, theBasePoint, theToMakeGroups );
2615
2616   TIDSortedElemSet elemsNodes[2];
2617   for ( int i = 0, nb = theNodes.length(); i < nb; ++i ) {
2618     SMDS_ElemIteratorPtr nIt = myMesh_i->GetElements( theNodes[i], SMESH::NODE );
2619     while ( nIt->more() ) elemsNodes[1].insert( nIt->next() );
2620   }
2621   for ( int i = 0, nb = theEdges.length(); i < nb; ++i )
2622     idSourceToSet( theEdges[i], getMeshDS(), elemsNodes[0], SMDSAbs_Edge );
2623   for ( int i = 0, nb = theFaces.length(); i < nb; ++i )
2624     idSourceToSet( theFaces[i], getMeshDS(), elemsNodes[0], SMDSAbs_Face );
2625
2626   TIDSortedElemSet* workElements = & elemsNodes[0], copyElements[2];
2627   SMDSAbs_ElementType previewType = SMDSAbs_All; //SMDSAbs_Face;
2628   if ( myIsPreviewMode )
2629   {
2630     // if ( (*elemsNodes.begin())->GetType() == SMDSAbs_Node )
2631     //   previewType = SMDSAbs_Edge;
2632
2633     SMDSAbs_ElementType select = SMDSAbs_All, avoid = SMDSAbs_Volume;
2634     TPreviewMesh * tmpMesh = getPreviewMesh( previewType );
2635     tmpMesh->Copy( elemsNodes[0], copyElements[0], select, avoid );
2636     tmpMesh->Copy( elemsNodes[1], copyElements[1], select, avoid );
2637     workElements = & copyElements[0];
2638
2639     params.SetNoGroups();
2640   }
2641   TPythonDump aPythonDump; // it is here to prevent dump of getGroups()
2642
2643   ::SMESH_MeshEditor::TTElemOfElemListMap aHistory;
2644   ::SMESH_MeshEditor::PGroupIDs groupIds =
2645       getEditor().ExtrusionSweep( workElements, params, aHistory );
2646
2647   SMESH::ListOfGroups * aGroups = theToMakeGroups ? getGroups( groupIds.get()) : 0;
2648
2649   declareMeshModified( /*isReComputeSafe=*/true ); // does not influence Compute()
2650
2651   if ( !myIsPreviewMode )
2652   {
2653     dumpGroupsList( aPythonDump, aGroups );
2654     aPythonDump << this<< ".ExtrusionSweepObjects( "
2655                 << theNodes             << ", "
2656                 << theEdges             << ", "
2657                 << theFaces             << ", "
2658                 << theStepVector        << ", "
2659                 << TVar( theNbOfSteps ) << ", "
2660                 << theToMakeGroups      << " )";
2661   }
2662   else
2663   {
2664     getPreviewMesh( previewType )->Remove( SMDSAbs_Volume );
2665   }
2666
2667   return aGroups ? aGroups : new SMESH::ListOfGroups;
2668
2669   SMESH_CATCH( SMESH::throwCorbaException );
2670   return 0;
2671 }
2672
2673 //=======================================================================
2674 //function : ExtrusionByNormal
2675 //purpose  :
2676 //=======================================================================
2677
2678 SMESH::ListOfGroups*
2679 SMESH_MeshEditor_i::ExtrusionByNormal(const SMESH::ListOfIDSources& objects,
2680                                       CORBA::Double                 stepSize,
2681                                       CORBA::Long                   nbOfSteps,
2682                                       CORBA::Boolean                byAverageNormal,
2683                                       CORBA::Boolean                useInputElemsOnly,
2684                                       CORBA::Boolean                makeGroups,
2685                                       CORBA::Short                  dim)
2686   throw (SALOME::SALOME_Exception)
2687 {
2688   SMESH_TRY;
2689   initData();
2690
2691   TPythonDump aPythonDump; // it is here to prevent dump of GetGroups()
2692
2693   ExtrusionParams params( stepSize, nbOfSteps, dim,
2694                           byAverageNormal, useInputElemsOnly, makeGroups );
2695
2696   SMDSAbs_ElementType elemType = ( dim == 1 ? SMDSAbs_Edge : SMDSAbs_Face );
2697   if ( objects.length() > 0 && !SMESH::DownCast<SMESH_Mesh_i*>( objects[0] ))
2698   {
2699     SMESH::array_of_ElementType_var elemTypes = objects[0]->GetTypes();
2700     if (( elemTypes->length() == 1 ) &&
2701         ( elemTypes[0] == SMESH::EDGE || elemTypes[0] == SMESH::FACE ))
2702       elemType = ( SMDSAbs_ElementType ) elemTypes[0];
2703   }
2704
2705   TIDSortedElemSet elemsNodes[2];
2706   for ( int i = 0, nb = objects.length(); i < nb; ++i )
2707     idSourceToSet( objects[i], getMeshDS(), elemsNodes[0], elemType );
2708
2709   TIDSortedElemSet* workElements = & elemsNodes[0], copyElements[2];
2710   SMDSAbs_ElementType previewType = SMDSAbs_Face;
2711   if ( myIsPreviewMode )
2712   {
2713     SMDSAbs_ElementType select = SMDSAbs_All, avoid = SMDSAbs_Volume;
2714     TPreviewMesh * tmpMesh = getPreviewMesh( previewType );
2715     tmpMesh->Copy( elemsNodes[0], copyElements[0], select, avoid );
2716     workElements = & copyElements[0];
2717
2718     params.SetNoGroups();
2719   }
2720
2721   ::SMESH_MeshEditor::TTElemOfElemListMap aHistory;
2722   ::SMESH_MeshEditor::PGroupIDs groupIds =
2723       getEditor().ExtrusionSweep( workElements, params, aHistory );
2724
2725   SMESH::ListOfGroups * aGroups = makeGroups ? getGroups( groupIds.get()) : 0;
2726
2727   if (!myIsPreviewMode) {
2728     dumpGroupsList(aPythonDump, aGroups);
2729     aPythonDump << this << ".ExtrusionByNormal( " << objects
2730                 << ", " << TVar( stepSize )
2731                 << ", " << TVar( nbOfSteps )
2732                 << ", " << byAverageNormal
2733                 << ", " << useInputElemsOnly
2734                 << ", " << makeGroups
2735                 << ", " << dim
2736                 << " )";
2737   }
2738   else
2739   {
2740     getPreviewMesh( previewType )->Remove( SMDSAbs_Volume );
2741   }
2742
2743   declareMeshModified( /*isReComputeSafe=*/true ); // does not influence Compute()
2744
2745   return aGroups ? aGroups : new SMESH::ListOfGroups;
2746
2747   SMESH_CATCH( SMESH::throwCorbaException );
2748   return 0;
2749 }
2750
2751 //=======================================================================
2752 //function : AdvancedExtrusion
2753 //purpose  :
2754 //=======================================================================
2755
2756 SMESH::ListOfGroups*
2757 SMESH_MeshEditor_i::AdvancedExtrusion(const SMESH::long_array & theIDsOfElements,
2758                                       const SMESH::DirStruct &  theStepVector,
2759                                       CORBA::Long               theNbOfSteps,
2760                                       CORBA::Long               theExtrFlags,
2761                                       CORBA::Double             theSewTolerance,
2762                                       CORBA::Boolean            theMakeGroups)
2763   throw (SALOME::SALOME_Exception)
2764 {
2765   SMESH_TRY;
2766   initData();
2767
2768   TPythonDump aPythonDump; // it is here to prevent dump of getGroups()
2769
2770   ExtrusionParams params( theStepVector, theNbOfSteps, theMakeGroups,
2771                           theExtrFlags, theSewTolerance );
2772
2773   TIDSortedElemSet elemsNodes[2];
2774   arrayToSet( theIDsOfElements, getMeshDS(), elemsNodes[0] );
2775
2776   ::SMESH_MeshEditor::TTElemOfElemListMap aHistory;
2777   ::SMESH_MeshEditor::PGroupIDs groupIds =
2778       getEditor().ExtrusionSweep( elemsNodes, params, aHistory );
2779
2780   SMESH::ListOfGroups * aGroups = theMakeGroups ? getGroups( groupIds.get()) : 0;
2781
2782   declareMeshModified( /*isReComputeSafe=*/true ); // does not influence Compute()
2783
2784   if ( !myIsPreviewMode ) {
2785     dumpGroupsList(aPythonDump, aGroups);
2786     aPythonDump << this << ".AdvancedExtrusion( "
2787                 << theIDsOfElements << ", "
2788                 << theStepVector << ", "
2789                 << theNbOfSteps << ", "
2790                 << theExtrFlags << ", "
2791                 << theSewTolerance << ", "
2792                 << theMakeGroups << " )";
2793   }
2794   else
2795   {
2796     getPreviewMesh()->Remove( SMDSAbs_Volume );
2797   }
2798
2799   return aGroups ? aGroups : new SMESH::ListOfGroups;
2800
2801   SMESH_CATCH( SMESH::throwCorbaException );
2802   return 0;
2803 }
2804
2805 //================================================================================
2806 /*!
2807  * \brief Convert extrusion error to IDL enum
2808  */
2809 //================================================================================
2810
2811 namespace
2812 {
2813 #define RETCASE(enm) case ::SMESH_MeshEditor::enm: return SMESH::SMESH_MeshEditor::enm;
2814
2815   SMESH::SMESH_MeshEditor::Extrusion_Error convExtrError( ::SMESH_MeshEditor::Extrusion_Error e )
2816   {
2817     switch ( e ) {
2818       RETCASE( EXTR_OK );
2819       RETCASE( EXTR_NO_ELEMENTS );
2820       RETCASE( EXTR_PATH_NOT_EDGE );
2821       RETCASE( EXTR_BAD_PATH_SHAPE );
2822       RETCASE( EXTR_BAD_STARTING_NODE );
2823       RETCASE( EXTR_BAD_ANGLES_NUMBER );
2824       RETCASE( EXTR_CANT_GET_TANGENT );
2825     }
2826     return SMESH::SMESH_MeshEditor::EXTR_OK;
2827   }
2828 }
2829
2830 //=======================================================================
2831 //function : extrusionAlongPath
2832 //purpose  :
2833 //=======================================================================
2834 SMESH::ListOfGroups*
2835 SMESH_MeshEditor_i::ExtrusionAlongPathObjects(const SMESH::ListOfIDSources & theNodes,
2836                                               const SMESH::ListOfIDSources & theEdges,
2837                                               const SMESH::ListOfIDSources & theFaces,
2838                                               SMESH::SMESH_IDSource_ptr      thePathMesh,
2839                                               GEOM::GEOM_Object_ptr          thePathShape,
2840                                               CORBA::Long                    theNodeStart,
2841                                               CORBA::Boolean                 theHasAngles,
2842                                               const SMESH::double_array &    theAngles,
2843                                               CORBA::Boolean                 theLinearVariation,
2844                                               CORBA::Boolean                 theHasRefPoint,
2845                                               const SMESH::PointStruct &     theRefPoint,
2846                                               bool                           theMakeGroups,
2847                                               SMESH::SMESH_MeshEditor::Extrusion_Error& theError)
2848   throw (SALOME::SALOME_Exception)
2849 {
2850   SMESH_TRY;
2851   initData();
2852
2853   SMESH::ListOfGroups_var aGroups = new SMESH::ListOfGroups;
2854
2855   theError = SMESH::SMESH_MeshEditor::EXTR_BAD_PATH_SHAPE;
2856   if ( thePathMesh->_is_nil() )
2857     return aGroups._retn();
2858
2859   // get a sub-mesh
2860   SMESH_subMesh* aSubMesh = 0;
2861   SMESH_Mesh_i* aMeshImp = SMESH::DownCast<SMESH_Mesh_i*>( thePathMesh );
2862   if ( thePathShape->_is_nil() )
2863   {
2864     // thePathMesh should be either a sub-mesh or a mesh with 1D elements only
2865     if ( SMESH_subMesh_i* sm = SMESH::DownCast<SMESH_subMesh_i*>( thePathMesh ))
2866     {
2867       SMESH::SMESH_Mesh_var mesh = thePathMesh->GetMesh();
2868       aMeshImp = SMESH::DownCast<SMESH_Mesh_i*>( mesh );
2869       if ( !aMeshImp ) return aGroups._retn();
2870       aSubMesh = aMeshImp->GetImpl().GetSubMeshContaining( sm->GetId() );
2871       if ( !aSubMesh ) return aGroups._retn();
2872     }
2873     else if ( !aMeshImp ||
2874               aMeshImp->NbEdges() != aMeshImp->NbElements() )
2875     {
2876       return aGroups._retn();
2877     }
2878   }
2879   else
2880   {
2881     if ( !aMeshImp ) return aGroups._retn();
2882     TopoDS_Shape aShape = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape( thePathShape );
2883     aSubMesh = aMeshImp->GetImpl().GetSubMesh( aShape );
2884     if ( !aSubMesh /*|| !aSubMesh->GetSubMeshDS()*/ )
2885       return aGroups._retn();
2886   }
2887
2888   SMDS_MeshNode* nodeStart =
2889     (SMDS_MeshNode*)aMeshImp->GetImpl().GetMeshDS()->FindNode(theNodeStart);
2890   if ( !nodeStart ) {
2891     theError = SMESH::SMESH_MeshEditor::EXTR_BAD_STARTING_NODE;
2892     return aGroups._retn();
2893   }
2894
2895   TIDSortedElemSet elemsNodes[2];
2896   for ( int i = 0, nb = theNodes.length(); i < nb; ++i ) {
2897     SMDS_ElemIteratorPtr nIt = myMesh_i->GetElements( theNodes[i], SMESH::NODE );
2898     while ( nIt->more() ) elemsNodes[1].insert( nIt->next() );
2899   }
2900   for ( int i = 0, nb = theEdges.length(); i < nb; ++i )
2901     idSourceToSet( theEdges[i], getMeshDS(), elemsNodes[0], SMDSAbs_Edge );
2902   for ( int i = 0, nb = theFaces.length(); i < nb; ++i )
2903     idSourceToSet( theFaces[i], getMeshDS(), elemsNodes[0], SMDSAbs_Face );
2904
2905   list<double> angles;
2906   for ( CORBA::ULong i = 0; i < theAngles.length(); i++ ) {
2907     angles.push_back( theAngles[i] );
2908   }
2909
2910   gp_Pnt refPnt( theRefPoint.x, theRefPoint.y, theRefPoint.z );
2911
2912   int nbOldGroups = myMesh->NbGroup();
2913
2914   TIDSortedElemSet* workElements = & elemsNodes[0], copyElements[2];
2915   if ( myIsPreviewMode )
2916   {
2917     SMDSAbs_ElementType select = SMDSAbs_All, avoid = SMDSAbs_Volume;
2918     TPreviewMesh * tmpMesh = getPreviewMesh();
2919     tmpMesh->Copy( elemsNodes[0], copyElements[0], select, avoid );
2920     tmpMesh->Copy( elemsNodes[1], copyElements[1], select, avoid );
2921     workElements = & copyElements[0];
2922     theMakeGroups = false;
2923   }
2924
2925   ::SMESH_MeshEditor::Extrusion_Error error;
2926   if ( !aSubMesh )
2927     error = getEditor().ExtrusionAlongTrack( workElements, &(aMeshImp->GetImpl()), nodeStart,
2928                                              theHasAngles, angles, theLinearVariation,
2929                                              theHasRefPoint, refPnt, theMakeGroups );
2930   else
2931     error = getEditor().ExtrusionAlongTrack( workElements, aSubMesh, nodeStart,
2932                                              theHasAngles, angles, theLinearVariation,
2933                                              theHasRefPoint, refPnt, theMakeGroups );
2934
2935   declareMeshModified( /*isReComputeSafe=*/true );
2936   theError = convExtrError( error );
2937
2938   TPythonDump aPythonDump; // it is here to prevent dump of getGroups()
2939   if ( theMakeGroups ) {
2940     list<int> groupIDs = myMesh->GetGroupIds();
2941     list<int>::iterator newBegin = groupIDs.begin();
2942     std::advance( newBegin, nbOldGroups ); // skip old groups
2943     groupIDs.erase( groupIDs.begin(), newBegin );
2944     aGroups = getGroups( & groupIDs );
2945     if ( ! &aGroups.in() ) aGroups = new SMESH::ListOfGroups;
2946   }
2947
2948   if ( !myIsPreviewMode ) {
2949     aPythonDump << "(" << aGroups << ", error) = "
2950                 << this << ".ExtrusionAlongPathObjects( "
2951                 << theNodes            << ", "
2952                 << theEdges            << ", "
2953                 << theFaces            << ", "
2954                 << thePathMesh         << ", "
2955                 << thePathShape        << ", "
2956                 << theNodeStart        << ", "
2957                 << theHasAngles        << ", "
2958                 << TVar( theAngles )   << ", "
2959                 << theLinearVariation  << ", "
2960                 << theHasRefPoint      << ", "
2961                 << "SMESH.PointStruct( "
2962                 << TVar( theHasRefPoint ? theRefPoint.x : 0 ) << ", "
2963                 << TVar( theHasRefPoint ? theRefPoint.y : 0 ) << ", "
2964                 << TVar( theHasRefPoint ? theRefPoint.z : 0 ) << " ), "
2965                 << theMakeGroups       << " )";
2966   }
2967   else
2968   {
2969     getPreviewMesh()->Remove( SMDSAbs_Volume );
2970   }
2971
2972   return aGroups._retn();
2973
2974   SMESH_CATCH( SMESH::throwCorbaException );
2975   return 0;
2976 }
2977
2978 //================================================================================
2979 /*!
2980  * \brief Compute rotation angles for ExtrusionAlongPath as linear variation
2981  * of given angles along path steps
2982  * \param PathMesh mesh containing a 1D sub-mesh on the edge, along
2983  *                which proceeds the extrusion
2984  * \param PathShape is shape(edge); as the mesh can be complex, the edge
2985  *                 is used to define the sub-mesh for the path
2986  */
2987 //================================================================================
2988
2989 SMESH::double_array*
2990 SMESH_MeshEditor_i::LinearAnglesVariation(SMESH::SMESH_Mesh_ptr       thePathMesh,
2991                                           GEOM::GEOM_Object_ptr       thePathShape,
2992                                           const SMESH::double_array & theAngles)
2993 {
2994   SMESH::double_array_var aResult = new SMESH::double_array();
2995   int nbAngles = theAngles.length();
2996   if ( nbAngles > 0 && !thePathMesh->_is_nil() && !thePathShape->_is_nil() )
2997   {
2998     SMESH_Mesh_i* aMeshImp = SMESH::DownCast<SMESH_Mesh_i*>( thePathMesh );
2999     TopoDS_Shape aShape = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape( thePathShape );
3000     SMESH_subMesh* aSubMesh = aMeshImp->GetImpl().GetSubMesh( aShape );
3001     if ( !aSubMesh || !aSubMesh->GetSubMeshDS())
3002       return aResult._retn();
3003     int nbSteps = aSubMesh->GetSubMeshDS()->NbElements();
3004     if ( nbSteps == nbAngles )
3005     {
3006       aResult.inout() = theAngles;
3007     }
3008     else
3009     {
3010       aResult->length( nbSteps );
3011       double rAn2St = double( nbAngles ) / double( nbSteps );
3012       double angPrev = 0, angle;
3013       for ( int iSt = 0; iSt < nbSteps; ++iSt )
3014       {
3015         double angCur = rAn2St * ( iSt+1 );
3016         double angCurFloor  = floor( angCur );
3017         double angPrevFloor = floor( angPrev );
3018         if ( angPrevFloor == angCurFloor )
3019           angle = rAn2St * theAngles[ int( angCurFloor ) ];
3020         else
3021         {
3022           int iP = int( angPrevFloor );
3023           double angPrevCeil = ceil(angPrev);
3024           angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
3025
3026           int iC = int( angCurFloor );
3027           if ( iC < nbAngles )
3028             angle += ( angCur - angCurFloor ) * theAngles[ iC ];
3029
3030           iP = int( angPrevCeil );
3031           while ( iC-- > iP )
3032             angle += theAngles[ iC ];
3033         }
3034         aResult[ iSt ] = angle;
3035         angPrev = angCur;
3036       }
3037     }
3038   }
3039   // Update Python script
3040   TPythonDump() << "rotAngles = " << theAngles;
3041   TPythonDump() << "rotAngles = " << this << ".LinearAnglesVariation( "
3042                 << thePathMesh  << ", "
3043                 << thePathShape << ", "
3044                 << "rotAngles )";
3045
3046   return aResult._retn();
3047 }
3048
3049 //=======================================================================
3050 //function : mirror
3051 //purpose  :
3052 //=======================================================================
3053
3054 SMESH::ListOfGroups*
3055 SMESH_MeshEditor_i::mirror(TIDSortedElemSet &                  theElements,
3056                            const SMESH::AxisStruct &           theAxis,
3057                            SMESH::SMESH_MeshEditor::MirrorType theMirrorType,
3058                            CORBA::Boolean                      theCopy,
3059                            bool                                theMakeGroups,
3060                            ::SMESH_Mesh*                       theTargetMesh)
3061   throw (SALOME::SALOME_Exception)
3062 {
3063   SMESH_TRY;
3064   initData();
3065
3066   gp_Pnt P ( theAxis.x, theAxis.y, theAxis.z );
3067   gp_Vec V ( theAxis.vx, theAxis.vy, theAxis.vz );
3068
3069   if ( theTargetMesh )
3070     theCopy = false;
3071
3072   gp_Trsf aTrsf;
3073   switch ( theMirrorType ) {
3074   case  SMESH::SMESH_MeshEditor::POINT:
3075     aTrsf.SetMirror( P );
3076     break;
3077   case  SMESH::SMESH_MeshEditor::AXIS:
3078     aTrsf.SetMirror( gp_Ax1( P, V ));
3079     break;
3080   default:
3081     aTrsf.SetMirror( gp_Ax2( P, V ));
3082   }
3083
3084   TIDSortedElemSet  copyElements;
3085   TIDSortedElemSet* workElements = & theElements;
3086
3087   if ( myIsPreviewMode )
3088   {
3089     TPreviewMesh * tmpMesh = getPreviewMesh();
3090     tmpMesh->Copy( theElements, copyElements);
3091     if ( !theCopy && !theTargetMesh )
3092     {
3093       TIDSortedElemSet elemsAround, elemsAroundCopy;
3094       getElementsAround( theElements, getMeshDS(), elemsAround );
3095       tmpMesh->Copy( elemsAround, elemsAroundCopy);
3096     }
3097     workElements = & copyElements;
3098     theMakeGroups = false;
3099   }
3100
3101   ::SMESH_MeshEditor::PGroupIDs groupIds =
3102       getEditor().Transform (*workElements, aTrsf, theCopy, theMakeGroups, theTargetMesh);
3103
3104   if ( theCopy && !myIsPreviewMode)
3105   {
3106     if ( theTargetMesh )
3107     {
3108       theTargetMesh->GetMeshDS()->Modified();
3109     }
3110     else
3111     {
3112       declareMeshModified( /*isReComputeSafe=*/false );
3113     }
3114   }
3115   return theMakeGroups ? getGroups(groupIds.get()) : 0;
3116
3117   SMESH_CATCH( SMESH::throwCorbaException );
3118   return 0;
3119 }
3120
3121 //=======================================================================
3122 //function : Mirror
3123 //purpose  :
3124 //=======================================================================
3125
3126 void SMESH_MeshEditor_i::Mirror(const SMESH::long_array &           theIDsOfElements,
3127                                 const SMESH::AxisStruct &           theAxis,
3128                                 SMESH::SMESH_MeshEditor::MirrorType theMirrorType,
3129                                 CORBA::Boolean                      theCopy)
3130   throw (SALOME::SALOME_Exception)
3131 {
3132   if ( !myIsPreviewMode ) {
3133     TPythonDump() << this << ".Mirror( "
3134                   << theIDsOfElements              << ", "
3135                   << theAxis                       << ", "
3136                   << mirrorTypeName(theMirrorType) << ", "
3137                   << theCopy                       << " )";
3138   }
3139   if ( theIDsOfElements.length() > 0 )
3140   {
3141     TIDSortedElemSet elements;
3142     arrayToSet(theIDsOfElements, getMeshDS(), elements);
3143     mirror(elements, theAxis, theMirrorType, theCopy, false);
3144   }
3145 }
3146
3147
3148 //=======================================================================
3149 //function : MirrorObject
3150 //purpose  :
3151 //=======================================================================
3152
3153 void SMESH_MeshEditor_i::MirrorObject(SMESH::SMESH_IDSource_ptr           theObject,
3154                                       const SMESH::AxisStruct &           theAxis,
3155                                       SMESH::SMESH_MeshEditor::MirrorType theMirrorType,
3156                                       CORBA::Boolean                      theCopy)
3157   throw (SALOME::SALOME_Exception)
3158 {
3159   if ( !myIsPreviewMode ) {
3160     TPythonDump() << this << ".MirrorObject( "
3161                   << theObject                     << ", "
3162                   << theAxis                       << ", "
3163                   << mirrorTypeName(theMirrorType) << ", "
3164                   << theCopy                       << " )";
3165   }
3166   TIDSortedElemSet elements;
3167
3168   bool emptyIfIsMesh = myIsPreviewMode ? false : true;
3169
3170   if (idSourceToSet(theObject, getMeshDS(), elements, SMDSAbs_All, emptyIfIsMesh))
3171     mirror(elements, theAxis, theMirrorType, theCopy, false);
3172 }
3173
3174 //=======================================================================
3175 //function : MirrorMakeGroups
3176 //purpose  :
3177 //=======================================================================
3178
3179 SMESH::ListOfGroups*
3180 SMESH_MeshEditor_i::MirrorMakeGroups(const SMESH::long_array&            theIDsOfElements,
3181                                      const SMESH::AxisStruct&            theMirror,
3182                                      SMESH::SMESH_MeshEditor::MirrorType theMirrorType)
3183   throw (SALOME::SALOME_Exception)
3184 {
3185   TPythonDump aPythonDump; // it is here to prevent dump of GetGroups()
3186
3187   SMESH::ListOfGroups * aGroups = 0;
3188   if ( theIDsOfElements.length() > 0 )
3189   {
3190     TIDSortedElemSet elements;
3191     arrayToSet(theIDsOfElements, getMeshDS(), elements);
3192     aGroups = mirror(elements, theMirror, theMirrorType, true, true);
3193   }
3194   if (!myIsPreviewMode) {
3195     dumpGroupsList(aPythonDump, aGroups);
3196     aPythonDump << this << ".MirrorMakeGroups( "
3197                 << theIDsOfElements              << ", "
3198                 << theMirror                     << ", "
3199                 << mirrorTypeName(theMirrorType) << " )";
3200   }
3201   return aGroups;
3202 }
3203
3204 //=======================================================================
3205 //function : MirrorObjectMakeGroups
3206 //purpose  :
3207 //=======================================================================
3208
3209 SMESH::ListOfGroups*
3210 SMESH_MeshEditor_i::MirrorObjectMakeGroups(SMESH::SMESH_IDSource_ptr           theObject,
3211                                            const SMESH::AxisStruct&            theMirror,
3212                                            SMESH::SMESH_MeshEditor::MirrorType theMirrorType)
3213   throw (SALOME::SALOME_Exception)
3214 {
3215   TPythonDump aPythonDump; // it is here to prevent dump of GetGroups()
3216
3217   SMESH::ListOfGroups * aGroups = 0;
3218   TIDSortedElemSet elements;
3219   if ( idSourceToSet(theObject, getMeshDS(), elements, SMDSAbs_All, /*emptyIfIsMesh=*/1))
3220     aGroups = mirror(elements, theMirror, theMirrorType, true, true);
3221
3222   if (!myIsPreviewMode)
3223   {
3224     dumpGroupsList(aPythonDump,aGroups);
3225     aPythonDump << this << ".MirrorObjectMakeGroups( "
3226                 << theObject                     << ", "
3227                 << theMirror                     << ", "
3228                 << mirrorTypeName(theMirrorType) << " )";
3229   }
3230   return aGroups;
3231 }
3232
3233 //=======================================================================
3234 //function : MirrorMakeMesh
3235 //purpose  :
3236 //=======================================================================
3237
3238 SMESH::SMESH_Mesh_ptr
3239 SMESH_MeshEditor_i::MirrorMakeMesh(const SMESH::long_array&            theIDsOfElements,
3240                                    const SMESH::AxisStruct&            theMirror,
3241                                    SMESH::SMESH_MeshEditor::MirrorType theMirrorType,
3242                                    CORBA::Boolean                      theCopyGroups,
3243                                    const char*                         theMeshName)
3244   throw (SALOME::SALOME_Exception)
3245 {
3246   SMESH_Mesh_i* mesh_i;
3247   SMESH::SMESH_Mesh_var mesh;
3248   { // open new scope to dump "MakeMesh" command
3249     // and then "GetGroups" using SMESH_Mesh::GetGroups()
3250
3251     TPythonDump pydump; // to prevent dump at mesh creation
3252
3253     mesh = makeMesh( theMeshName );
3254     mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh );
3255     if (mesh_i && theIDsOfElements.length() > 0 )
3256     {
3257       TIDSortedElemSet elements;
3258       arrayToSet(theIDsOfElements, getMeshDS(), elements);
3259       mirror(elements, theMirror, theMirrorType,
3260              false, theCopyGroups, & mesh_i->GetImpl());
3261       mesh_i->CreateGroupServants();
3262     }
3263
3264     if (!myIsPreviewMode) {
3265       pydump << mesh << " = " << this << ".MirrorMakeMesh( "
3266              << theIDsOfElements              << ", "
3267              << theMirror                     << ", "
3268              << mirrorTypeName(theMirrorType) << ", "
3269              << theCopyGroups                 << ", '"
3270              << theMeshName                   << "' )";
3271     }
3272   }
3273
3274   //dump "GetGroups"
3275   if (!myIsPreviewMode && mesh_i)
3276     mesh_i->GetGroups();
3277
3278   return mesh._retn();
3279 }
3280
3281 //=======================================================================
3282 //function : MirrorObjectMakeMesh
3283 //purpose  :
3284 //=======================================================================
3285
3286 SMESH::SMESH_Mesh_ptr
3287 SMESH_MeshEditor_i::MirrorObjectMakeMesh(SMESH::SMESH_IDSource_ptr           theObject,
3288                                          const SMESH::AxisStruct&            theMirror,
3289                                          SMESH::SMESH_MeshEditor::MirrorType theMirrorType,
3290                                          CORBA::Boolean                      theCopyGroups,
3291                                          const char*                         theMeshName)
3292   throw (SALOME::SALOME_Exception)
3293 {
3294   SMESH_Mesh_i* mesh_i;
3295   SMESH::SMESH_Mesh_var mesh;
3296   { // open new scope to dump "MakeMesh" command
3297     // and then "GetGroups" using SMESH_Mesh::GetGroups()
3298
3299     TPythonDump pydump; // to prevent dump at mesh creation
3300
3301     mesh = makeMesh( theMeshName );
3302     mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh );
3303     TIDSortedElemSet elements;
3304     if ( mesh_i &&
3305          idSourceToSet(theObject, getMeshDS(), elements, SMDSAbs_All, /*emptyIfIsMesh=*/1))
3306     {
3307       mirror(elements, theMirror, theMirrorType,
3308              false, theCopyGroups, & mesh_i->GetImpl());
3309       mesh_i->CreateGroupServants();
3310     }
3311     if (!myIsPreviewMode) {
3312       pydump << mesh << " = " << this << ".MirrorObjectMakeMesh( "
3313              << theObject                     << ", "
3314              << theMirror                     << ", "
3315              << mirrorTypeName(theMirrorType) << ", "
3316              << theCopyGroups                 << ", '"
3317              << theMeshName                   << "' )";
3318     }
3319   }
3320
3321   //dump "GetGroups"
3322   if (!myIsPreviewMode && mesh_i)
3323     mesh_i->GetGroups();
3324
3325   return mesh._retn();
3326 }
3327
3328 //=======================================================================
3329 //function : translate
3330 //purpose  :
3331 //=======================================================================
3332
3333 SMESH::ListOfGroups*
3334 SMESH_MeshEditor_i::translate(TIDSortedElemSet        & theElements,
3335                               const SMESH::DirStruct &  theVector,
3336                               CORBA::Boolean            theCopy,
3337                               bool                      theMakeGroups,
3338                               ::SMESH_Mesh*             theTargetMesh)
3339   throw (SALOME::SALOME_Exception)
3340 {
3341   SMESH_TRY;
3342   initData();
3343
3344   if ( theTargetMesh )
3345     theCopy = false;
3346
3347   gp_Trsf aTrsf;
3348   const SMESH::PointStruct * P = &theVector.PS;
3349   aTrsf.SetTranslation( gp_Vec( P->x, P->y, P->z ));
3350
3351   TIDSortedElemSet  copyElements;
3352   TIDSortedElemSet* workElements = &theElements;
3353
3354   if ( myIsPreviewMode )
3355   {
3356     TPreviewMesh * tmpMesh = getPreviewMesh();
3357     tmpMesh->Copy( theElements, copyElements);
3358     if ( !theCopy && !theTargetMesh )
3359     {
3360       TIDSortedElemSet elemsAround, elemsAroundCopy;
3361       getElementsAround( theElements, getMeshDS(), elemsAround );
3362       tmpMesh->Copy( elemsAround, elemsAroundCopy);
3363     }
3364     workElements = & copyElements;
3365     theMakeGroups = false;
3366   }
3367
3368   ::SMESH_MeshEditor::PGroupIDs groupIds =
3369       getEditor().Transform (*workElements, aTrsf, theCopy, theMakeGroups, theTargetMesh);
3370
3371   if ( theCopy && !myIsPreviewMode )
3372   {
3373     if ( theTargetMesh )
3374     {
3375       theTargetMesh->GetMeshDS()->Modified();
3376     }
3377     else
3378     {
3379       declareMeshModified( /*isReComputeSafe=*/false );
3380     }
3381   }
3382
3383   return theMakeGroups ? getGroups(groupIds.get()) : 0;
3384
3385   SMESH_CATCH( SMESH::throwCorbaException );
3386   return 0;
3387 }
3388
3389 //=======================================================================
3390 //function : Translate
3391 //purpose  :
3392 //=======================================================================
3393
3394 void SMESH_MeshEditor_i::Translate(const SMESH::long_array & theIDsOfElements,
3395                                    const SMESH::DirStruct &  theVector,
3396                                    CORBA::Boolean            theCopy)
3397   throw (SALOME::SALOME_Exception)
3398 {
3399   if (!myIsPreviewMode) {
3400     TPythonDump() << this << ".Translate( "
3401                   << theIDsOfElements << ", "
3402                   << theVector        << ", "
3403                   << theCopy          << " )";
3404   }
3405   if (theIDsOfElements.length()) {
3406     TIDSortedElemSet elements;
3407     arrayToSet(theIDsOfElements, getMeshDS(), elements);
3408     translate(elements, theVector, theCopy, false);
3409   }
3410 }
3411
3412 //=======================================================================
3413 //function : TranslateObject
3414 //purpose  :
3415 //=======================================================================
3416
3417 void SMESH_MeshEditor_i::TranslateObject(SMESH::SMESH_IDSource_ptr theObject,
3418                                          const SMESH::DirStruct &  theVector,
3419                                          CORBA::Boolean            theCopy)
3420   throw (SALOME::SALOME_Exception)
3421 {
3422   if (!myIsPreviewMode) {
3423     TPythonDump() << this << ".TranslateObject( "
3424                   << theObject << ", "
3425                   << theVector << ", "
3426                   << theCopy   << " )";
3427   }
3428   TIDSortedElemSet elements;
3429
3430   bool emptyIfIsMesh = myIsPreviewMode ? false : true;
3431
3432   if (idSourceToSet(theObject, getMeshDS(), elements, SMDSAbs_All, emptyIfIsMesh))
3433     translate(elements, theVector, theCopy, false);
3434 }
3435
3436 //=======================================================================
3437 //function : TranslateMakeGroups
3438 //purpose  :
3439 //=======================================================================
3440
3441 SMESH::ListOfGroups*
3442 SMESH_MeshEditor_i::TranslateMakeGroups(const SMESH::long_array& theIDsOfElements,
3443                                         const SMESH::DirStruct&  theVector)
3444   throw (SALOME::SALOME_Exception)
3445 {
3446   TPythonDump aPythonDump; // it is here to prevent dump of GetGroups()
3447
3448   SMESH::ListOfGroups * aGroups = 0;
3449   if (theIDsOfElements.length()) {
3450     TIDSortedElemSet elements;
3451     arrayToSet(theIDsOfElements, getMeshDS(), elements);
3452     aGroups = translate(elements,theVector,true,true);
3453   }
3454   if (!myIsPreviewMode) {
3455     dumpGroupsList(aPythonDump, aGroups);
3456     aPythonDump << this << ".TranslateMakeGroups( "
3457                 << theIDsOfElements << ", "
3458                 << theVector        << " )";
3459   }
3460   return aGroups;
3461 }
3462
3463 //=======================================================================
3464 //function : TranslateObjectMakeGroups
3465 //purpose  :
3466 //=======================================================================
3467
3468 SMESH::ListOfGroups*
3469 SMESH_MeshEditor_i::TranslateObjectMakeGroups(SMESH::SMESH_IDSource_ptr theObject,
3470                                               const SMESH::DirStruct&   theVector)
3471   throw (SALOME::SALOME_Exception)
3472 {
3473   TPythonDump aPythonDump; // it is here to prevent dump of GetGroups()
3474
3475   SMESH::ListOfGroups * aGroups = 0;
3476   TIDSortedElemSet elements;
3477   if (idSourceToSet(theObject, getMeshDS(), elements, SMDSAbs_All, /*emptyIfIsMesh=*/1))
3478     aGroups = translate(elements, theVector, true, true);
3479
3480   if (!myIsPreviewMode) {
3481     dumpGroupsList(aPythonDump, aGroups);
3482     aPythonDump << this << ".TranslateObjectMakeGroups( "
3483                 << theObject << ", "
3484                 << theVector << " )";
3485   }
3486   return aGroups;
3487 }
3488
3489 //=======================================================================
3490 //function : TranslateMakeMesh
3491 //purpose  :
3492 //=======================================================================
3493
3494 SMESH::SMESH_Mesh_ptr
3495 SMESH_MeshEditor_i::TranslateMakeMesh(const SMESH::long_array& theIDsOfElements,
3496                                       const SMESH::DirStruct&  theVector,
3497                                       CORBA::Boolean           theCopyGroups,
3498                                       const char*              theMeshName)
3499   throw (SALOME::SALOME_Exception)
3500 {
3501   SMESH_Mesh_i* mesh_i;
3502   SMESH::SMESH_Mesh_var mesh;
3503
3504   { // open new scope to dump "MakeMesh" command
3505     // and then "GetGroups" using SMESH_Mesh::GetGroups()
3506
3507     TPythonDump pydump; // to prevent dump at mesh creation
3508
3509     mesh = makeMesh( theMeshName );
3510     mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh );
3511
3512     if ( mesh_i && theIDsOfElements.length() )
3513     {
3514       TIDSortedElemSet elements;
3515       arrayToSet(theIDsOfElements, getMeshDS(), elements);
3516       translate(elements, theVector, false, theCopyGroups, & mesh_i->GetImpl());
3517       mesh_i->CreateGroupServants();
3518     }
3519
3520     if ( !myIsPreviewMode ) {
3521       pydump << mesh << " = " << this << ".TranslateMakeMesh( "
3522              << theIDsOfElements << ", "
3523              << theVector        << ", "
3524              << theCopyGroups    << ", '"
3525              << theMeshName      << "' )";
3526     }
3527   }
3528
3529   //dump "GetGroups"
3530   if (!myIsPreviewMode && mesh_i)
3531     mesh_i->GetGroups();
3532
3533   return mesh._retn();
3534 }
3535
3536 //=======================================================================
3537 //function : TranslateObjectMakeMesh
3538 //purpose  :
3539 //=======================================================================
3540
3541 SMESH::SMESH_Mesh_ptr
3542 SMESH_MeshEditor_i::TranslateObjectMakeMesh(SMESH::SMESH_IDSource_ptr theObject,
3543                                             const SMESH::DirStruct&   theVector,
3544                                             CORBA::Boolean            theCopyGroups,
3545                                             const char*               theMeshName)
3546   throw (SALOME::SALOME_Exception)
3547 {
3548   SMESH_TRY;
3549   SMESH_Mesh_i* mesh_i;
3550   SMESH::SMESH_Mesh_var mesh;
3551   { // open new scope to dump "MakeMesh" command
3552     // and then "GetGroups" using SMESH_Mesh::GetGroups()
3553
3554     TPythonDump pydump; // to prevent dump at mesh creation
3555     mesh = makeMesh( theMeshName );
3556     mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh );
3557
3558     TIDSortedElemSet elements;
3559     if ( mesh_i &&
3560          idSourceToSet(theObject, getMeshDS(), elements, SMDSAbs_All, /*emptyIfIsMesh=*/1))
3561     {
3562       translate(elements, theVector,false, theCopyGroups, & mesh_i->GetImpl());
3563       mesh_i->CreateGroupServants();
3564     }
3565     if ( !myIsPreviewMode ) {
3566       pydump << mesh << " = " << this << ".TranslateObjectMakeMesh( "
3567              << theObject     << ", "
3568              << theVector     << ", "
3569              << theCopyGroups << ", '"
3570              << theMeshName   << "' )";
3571     }
3572   }
3573
3574   // dump "GetGroups"
3575   if (!myIsPreviewMode && mesh_i)
3576     mesh_i->GetGroups();
3577
3578   return mesh._retn();
3579
3580   SMESH_CATCH( SMESH::throwCorbaException );
3581   return 0;
3582 }
3583
3584 //=======================================================================
3585 //function : rotate
3586 //purpose  :
3587 //=======================================================================
3588
3589 SMESH::ListOfGroups*
3590 SMESH_MeshEditor_i::rotate(TIDSortedElemSet &        theElements,
3591                            const SMESH::AxisStruct & theAxis,
3592                            CORBA::Double             theAngle,
3593                            CORBA::Boolean            theCopy,
3594                            bool                      theMakeGroups,
3595                            ::SMESH_Mesh*             theTargetMesh)
3596   throw (SALOME::SALOME_Exception)
3597 {
3598   SMESH_TRY;
3599   initData();
3600
3601   if ( theTargetMesh )
3602     theCopy = false;
3603
3604   gp_Pnt P ( theAxis.x, theAxis.y, theAxis.z );
3605   gp_Vec V ( theAxis.vx, theAxis.vy, theAxis.vz );
3606
3607   gp_Trsf aTrsf;
3608   aTrsf.SetRotation( gp_Ax1( P, V ), theAngle);
3609
3610   TIDSortedElemSet  copyElements;
3611   TIDSortedElemSet* workElements = &theElements;
3612   if ( myIsPreviewMode ) {
3613     TPreviewMesh * tmpMesh = getPreviewMesh();
3614     tmpMesh->Copy( theElements, copyElements );
3615     if ( !theCopy && !theTargetMesh )
3616     {
3617       TIDSortedElemSet elemsAround, elemsAroundCopy;
3618       getElementsAround( theElements, getMeshDS(), elemsAround );
3619       tmpMesh->Copy( elemsAround, elemsAroundCopy);
3620     }
3621     workElements = &copyElements;
3622     theMakeGroups = false;
3623   }
3624
3625   ::SMESH_MeshEditor::PGroupIDs groupIds =
3626       getEditor().Transform (*workElements, aTrsf, theCopy, theMakeGroups, theTargetMesh);
3627
3628   if ( theCopy && !myIsPreviewMode)
3629   {
3630     if ( theTargetMesh ) theTargetMesh->GetMeshDS()->Modified();
3631     else                 declareMeshModified( /*isReComputeSafe=*/false );
3632   }
3633
3634   return theMakeGroups ? getGroups(groupIds.get()) : 0;
3635
3636   SMESH_CATCH( SMESH::throwCorbaException );
3637   return 0;
3638 }
3639
3640 //=======================================================================
3641 //function : Rotate
3642 //purpose  :
3643 //=======================================================================
3644
3645 void SMESH_MeshEditor_i::Rotate(const SMESH::long_array & theIDsOfElements,
3646                                 const SMESH::AxisStruct & theAxis,
3647                                 CORBA::Double             theAngle,
3648                                 CORBA::Boolean            theCopy)
3649   throw (SALOME::SALOME_Exception)
3650 {
3651   if (!myIsPreviewMode) {
3652     TPythonDump() << this << ".Rotate( "
3653                   << theIDsOfElements << ", "
3654                   << theAxis          << ", "
3655                   << TVar( theAngle ) << ", "
3656                   << theCopy          << " )";
3657   }
3658   if (theIDsOfElements.length() > 0)
3659   {
3660     TIDSortedElemSet elements;
3661     arrayToSet(theIDsOfElements, getMeshDS(), elements);
3662     rotate(elements,theAxis,theAngle,theCopy,false);
3663   }
3664 }
3665
3666 //=======================================================================
3667 //function : RotateObject
3668 //purpose  :
3669 //=======================================================================
3670
3671 void SMESH_MeshEditor_i::RotateObject(SMESH::SMESH_IDSource_ptr theObject,
3672                                       const SMESH::AxisStruct & theAxis,
3673                                       CORBA::Double             theAngle,
3674                                       CORBA::Boolean            theCopy)
3675   throw (SALOME::SALOME_Exception)
3676 {
3677   if ( !myIsPreviewMode ) {
3678     TPythonDump() << this << ".RotateObject( "
3679                   << theObject        << ", "
3680                   << theAxis          << ", "
3681                   << TVar( theAngle ) << ", "
3682                   << theCopy          << " )";
3683   }
3684   TIDSortedElemSet elements;
3685   bool emptyIfIsMesh = myIsPreviewMode ? false : true;
3686   if (idSourceToSet(theObject, getMeshDS(), elements, SMDSAbs_All, emptyIfIsMesh))
3687     rotate(elements,theAxis,theAngle,theCopy,false);
3688 }
3689
3690 //=======================================================================
3691 //function : RotateMakeGroups
3692 //purpose  :
3693 //=======================================================================
3694
3695 SMESH::ListOfGroups*
3696 SMESH_MeshEditor_i::RotateMakeGroups(const SMESH::long_array& theIDsOfElements,
3697                                      const SMESH::AxisStruct& theAxis,
3698                                      CORBA::Double            theAngle)
3699   throw (SALOME::SALOME_Exception)
3700 {
3701   TPythonDump aPythonDump; // it is here to prevent dump of GetGroups()
3702
3703   SMESH::ListOfGroups * aGroups = 0;
3704   if (theIDsOfElements.length() > 0)
3705   {
3706     TIDSortedElemSet elements;
3707     arrayToSet(theIDsOfElements, getMeshDS(), elements);
3708     aGroups = rotate(elements,theAxis,theAngle,true,true);
3709   }
3710   if (!myIsPreviewMode) {
3711     dumpGroupsList(aPythonDump, aGroups);
3712     aPythonDump << this << ".RotateMakeGroups( "
3713                 << theIDsOfElements << ", "
3714                 << theAxis          << ", "
3715                 << TVar( theAngle ) << " )";
3716   }
3717   return aGroups;
3718 }
3719
3720 //=======================================================================
3721 //function : RotateObjectMakeGroups
3722 //purpose  :
3723 //=======================================================================
3724
3725 SMESH::ListOfGroups*
3726 SMESH_MeshEditor_i::RotateObjectMakeGroups(SMESH::SMESH_IDSource_ptr theObject,
3727                                            const SMESH::AxisStruct&  theAxis,
3728                                            CORBA::Double             theAngle)
3729   throw (SALOME::SALOME_Exception)
3730 {
3731   TPythonDump aPythonDump; // it is here to prevent dump of GetGroups()
3732
3733   SMESH::ListOfGroups * aGroups = 0;
3734   TIDSortedElemSet elements;
3735   if (idSourceToSet(theObject, getMeshDS(), elements, SMDSAbs_All, /*emptyIfIsMesh=*/1))
3736     aGroups = rotate(elements, theAxis, theAngle, true, true);
3737
3738   if (!myIsPreviewMode) {
3739     dumpGroupsList(aPythonDump, aGroups);
3740     aPythonDump << this << ".RotateObjectMakeGroups( "
3741                 << theObject        << ", "
3742                 << theAxis          << ", "
3743                 << TVar( theAngle ) << " )";
3744   }
3745   return aGroups;
3746 }
3747
3748 //=======================================================================
3749 //function : RotateMakeMesh
3750 //purpose  :
3751 //=======================================================================
3752
3753 SMESH::SMESH_Mesh_ptr
3754 SMESH_MeshEditor_i::RotateMakeMesh(const SMESH::long_array& theIDsOfElements,
3755                                    const SMESH::AxisStruct& theAxis,
3756                                    CORBA::Double            theAngleInRadians,
3757                                    CORBA::Boolean           theCopyGroups,
3758                                    const char*              theMeshName)
3759   throw (SALOME::SALOME_Exception)
3760 {
3761   SMESH_TRY;
3762   SMESH::SMESH_Mesh_var mesh;
3763   SMESH_Mesh_i* mesh_i;
3764
3765   { // open new scope to dump "MakeMesh" command
3766     // and then "GetGroups" using SMESH_Mesh::GetGroups()
3767
3768     TPythonDump pydump; // to prevent dump at mesh creation
3769
3770     mesh = makeMesh( theMeshName );
3771     mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh );
3772
3773     if ( mesh_i && theIDsOfElements.length() > 0 )
3774     {
3775       TIDSortedElemSet elements;
3776       arrayToSet(theIDsOfElements, getMeshDS(), elements);
3777       rotate(elements, theAxis, theAngleInRadians,
3778              false, theCopyGroups, & mesh_i->GetImpl());
3779       mesh_i->CreateGroupServants();
3780     }
3781     if ( !myIsPreviewMode ) {
3782       pydump << mesh << " = " << this << ".RotateMakeMesh( "
3783              << theIDsOfElements          << ", "
3784              << theAxis                   << ", "
3785              << TVar( theAngleInRadians ) << ", "
3786              << theCopyGroups             << ", '"
3787              << theMeshName               << "' )";
3788     }
3789   }
3790
3791   // dump "GetGroups"
3792   if (!myIsPreviewMode && mesh_i && theIDsOfElements.length() > 0 )
3793     mesh_i->GetGroups();
3794
3795   return mesh._retn();
3796
3797   SMESH_CATCH( SMESH::throwCorbaException );
3798   return 0;
3799 }
3800
3801 //=======================================================================
3802 //function : RotateObjectMakeMesh
3803 //purpose  :
3804 //=======================================================================
3805
3806 SMESH::SMESH_Mesh_ptr
3807 SMESH_MeshEditor_i::RotateObjectMakeMesh(SMESH::SMESH_IDSource_ptr theObject,
3808                                          const SMESH::AxisStruct&  theAxis,
3809                                          CORBA::Double             theAngleInRadians,
3810                                          CORBA::Boolean            theCopyGroups,
3811                                          const char*               theMeshName)
3812   throw (SALOME::SALOME_Exception)
3813 {
3814   SMESH_TRY;
3815   SMESH::SMESH_Mesh_var mesh;
3816   SMESH_Mesh_i* mesh_i;
3817
3818   {// open new scope to dump "MakeMesh" command
3819    // and then "GetGroups" using SMESH_Mesh::GetGroups()
3820
3821     TPythonDump pydump; // to prevent dump at mesh creation
3822     mesh = makeMesh( theMeshName );
3823     mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh );
3824
3825     TIDSortedElemSet elements;
3826     if (mesh_i &&
3827         idSourceToSet(theObject, getMeshDS(), elements, SMDSAbs_All, /*emptyIfIsMesh=*/1))
3828     {
3829       rotate(elements, theAxis, theAngleInRadians,
3830              false, theCopyGroups, & mesh_i->GetImpl());
3831       mesh_i->CreateGroupServants();
3832     }
3833     if ( !myIsPreviewMode ) {
3834       pydump << mesh << " = " << this << ".RotateObjectMakeMesh( "
3835              << theObject                 << ", "
3836              << theAxis                   << ", "
3837              << TVar( theAngleInRadians ) << ", "
3838              << theCopyGroups             << ", '"
3839              << theMeshName               << "' )";
3840     }
3841   }
3842
3843   // dump "GetGroups"
3844   if (!myIsPreviewMode && mesh_i)
3845     mesh_i->GetGroups();
3846
3847   return mesh._retn();
3848
3849   SMESH_CATCH( SMESH::throwCorbaException );
3850   return 0;
3851 }
3852
3853 //=======================================================================
3854 //function : scale
3855 //purpose  :
3856 //=======================================================================
3857
3858 SMESH::ListOfGroups*
3859 SMESH_MeshEditor_i::scale(SMESH::SMESH_IDSource_ptr  theObject,
3860                           const SMESH::PointStruct&  thePoint,
3861                           const SMESH::double_array& theScaleFact,
3862                           CORBA::Boolean             theCopy,
3863                           bool                       theMakeGroups,
3864                           ::SMESH_Mesh*              theTargetMesh)
3865   throw (SALOME::SALOME_Exception)
3866 {
3867   SMESH_TRY;
3868   initData();
3869   if ( theScaleFact.length() < 1 )
3870     THROW_SALOME_CORBA_EXCEPTION("Scale factor not given", SALOME::BAD_PARAM);
3871   if ( theScaleFact.length() == 2 )
3872     THROW_SALOME_CORBA_EXCEPTION("Invalid nb of scale factors : 2", SALOME::BAD_PARAM);
3873
3874   if ( theTargetMesh )
3875     theCopy = false;
3876
3877   TIDSortedElemSet elements;
3878   bool emptyIfIsMesh = myIsPreviewMode ? false : true;
3879   if ( !idSourceToSet(theObject, getMeshDS(), elements, SMDSAbs_All, emptyIfIsMesh))
3880     return 0;
3881
3882   double S[3] = {
3883     theScaleFact[0],
3884     (theScaleFact.length() == 1) ? theScaleFact[0] : theScaleFact[1],
3885     (theScaleFact.length() == 1) ? theScaleFact[0] : theScaleFact[2],
3886   };
3887   gp_Trsf aTrsf;
3888
3889 #if OCC_VERSION_LARGE > 0x06070100
3890   // fight against orthogonalization
3891   // aTrsf.SetValues( S[0], 0,    0,    thePoint.x * (1-S[0]),
3892   //                  0,    S[1], 0,    thePoint.y * (1-S[1]),
3893   //                  0,    0,    S[2], thePoint.z * (1-S[2]) );
3894   aTrsf.SetScale( gp::Origin(), 1.0 ); // set form which is used to make group names
3895   gp_XYZ & loc = ( gp_XYZ& ) aTrsf.TranslationPart();
3896   gp_Mat & M   = ( gp_Mat& ) aTrsf.HVectorialPart();
3897   loc.SetCoord( thePoint.x * (1-S[0]),
3898                 thePoint.y * (1-S[1]),
3899                 thePoint.z * (1-S[2]));
3900   M.SetDiagonal( S[0], S[1], S[2] );
3901
3902 #else
3903   double tol = std::numeric_limits<double>::max();
3904   aTrsf.SetValues( S[0], 0,    0,    thePoint.x * (1-S[0]),
3905                    0,    S[1], 0,    thePoint.y * (1-S[1]),
3906                    0,    0,    S[2], thePoint.z * (1-S[2]),   tol, tol);
3907 #endif
3908
3909   TIDSortedElemSet  copyElements;
3910   TIDSortedElemSet* workElements = &elements;
3911   if ( myIsPreviewMode )
3912   {
3913     TPreviewMesh * tmpMesh = getPreviewMesh();
3914     tmpMesh->Copy( elements, copyElements);
3915     if ( !theCopy && !theTargetMesh )
3916     {
3917       TIDSortedElemSet elemsAround, elemsAroundCopy;
3918       getElementsAround( elements, getMeshDS(), elemsAround );
3919       tmpMesh->Copy( elemsAround, elemsAroundCopy);
3920     }
3921     workElements = & copyElements;
3922     theMakeGroups = false;
3923   }
3924
3925   ::SMESH_MeshEditor::PGroupIDs groupIds =
3926       getEditor().Transform (*workElements, aTrsf, theCopy, theMakeGroups, theTargetMesh);
3927
3928   if ( theCopy && !myIsPreviewMode )
3929   {
3930     if ( theTargetMesh ) theTargetMesh->GetMeshDS()->Modified();
3931     else                 declareMeshModified( /*isReComputeSafe=*/false );
3932   }
3933   return theMakeGroups ? getGroups(groupIds.get()) : 0;
3934
3935   SMESH_CATCH( SMESH::throwCorbaException );
3936   return 0;
3937 }
3938
3939 //=======================================================================
3940 //function : Scale
3941 //purpose  :
3942 //=======================================================================
3943
3944 void SMESH_MeshEditor_i::Scale(SMESH::SMESH_IDSource_ptr  theObject,
3945                                const SMESH::PointStruct&  thePoint,
3946                                const SMESH::double_array& theScaleFact,
3947                                CORBA::Boolean             theCopy)
3948   throw (SALOME::SALOME_Exception)
3949 {
3950   if ( !myIsPreviewMode ) {
3951     TPythonDump() << this << ".Scale( "
3952                   << theObject            << ", "
3953                   << thePoint             << ", "
3954                   << TVar( theScaleFact ) << ", "
3955                   << theCopy              << " )";
3956   }
3957   scale(theObject, thePoint, theScaleFact, theCopy, false);
3958 }
3959
3960
3961 //=======================================================================
3962 //function : ScaleMakeGroups
3963 //purpose  :
3964 //=======================================================================
3965
3966 SMESH::ListOfGroups*
3967 SMESH_MeshEditor_i::ScaleMakeGroups(SMESH::SMESH_IDSource_ptr  theObject,
3968                                     const SMESH::PointStruct&  thePoint,
3969                                     const SMESH::double_array& theScaleFact)
3970   throw (SALOME::SALOME_Exception)
3971 {
3972   TPythonDump aPythonDump; // it is here to prevent dump of GetGroups()
3973
3974   SMESH::ListOfGroups * aGroups = scale(theObject, thePoint, theScaleFact, true, true);
3975   if (!myIsPreviewMode) {
3976     dumpGroupsList(aPythonDump, aGroups);
3977     aPythonDump << this << ".Scale("
3978                 << theObject            << ","
3979                 << thePoint             << ","
3980                 << TVar( theScaleFact ) << ",True,True)";
3981   }
3982   return aGroups;
3983 }
3984
3985
3986 //=======================================================================
3987 //function : ScaleMakeMesh
3988 //purpose  :
3989 //=======================================================================
3990
3991 SMESH::SMESH_Mesh_ptr
3992 SMESH_MeshEditor_i::ScaleMakeMesh(SMESH::SMESH_IDSource_ptr  theObject,
3993                                   const SMESH::PointStruct&  thePoint,
3994                                   const SMESH::double_array& theScaleFact,
3995                                   CORBA::Boolean             theCopyGroups,
3996                                   const char*                theMeshName)
3997   throw (SALOME::SALOME_Exception)
3998 {
3999   SMESH_Mesh_i* mesh_i;
4000   SMESH::SMESH_Mesh_var mesh;
4001   { // open new scope to dump "MakeMesh" command
4002     // and then "GetGroups" using SMESH_Mesh::GetGroups()
4003
4004     TPythonDump pydump; // to prevent dump at mesh creation
4005     mesh = makeMesh( theMeshName );
4006     mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh );
4007
4008     if ( mesh_i )
4009     {
4010       scale(theObject, thePoint, theScaleFact,false, theCopyGroups, & mesh_i->GetImpl());
4011       mesh_i->CreateGroupServants();
4012     }
4013     if ( !myIsPreviewMode )
4014       pydump << mesh << " = " << this << ".ScaleMakeMesh( "
4015              << theObject            << ", "
4016              << thePoint             << ", "
4017              << TVar( theScaleFact ) << ", "
4018              << theCopyGroups        << ", '"
4019              << theMeshName          << "' )";
4020   }
4021
4022   // dump "GetGroups"
4023   if (!myIsPreviewMode && mesh_i)
4024     mesh_i->GetGroups();
4025
4026   return mesh._retn();
4027 }
4028
4029
4030 //=======================================================================
4031 //function : findCoincidentNodes
4032 //purpose  :
4033 //=======================================================================
4034
4035 void SMESH_MeshEditor_i::
4036 findCoincidentNodes (TIDSortedNodeSet &             Nodes,
4037                      CORBA::Double                  Tolerance,
4038                      SMESH::array_of_long_array_out GroupsOfNodes,
4039                      CORBA::Boolean                 SeparateCornersAndMedium)
4040 {
4041   ::SMESH_MeshEditor::TListOfListOfNodes aListOfListOfNodes;
4042   getEditor().FindCoincidentNodes( Nodes, Tolerance, aListOfListOfNodes, SeparateCornersAndMedium );
4043
4044   GroupsOfNodes = new SMESH::array_of_long_array;
4045   GroupsOfNodes->length( aListOfListOfNodes.size() );
4046   ::SMESH_MeshEditor::TListOfListOfNodes::iterator llIt = aListOfListOfNodes.begin();
4047   for ( CORBA::Long i = 0; llIt != aListOfListOfNodes.end(); llIt++, i++ )
4048   {
4049     list< const SMDS_MeshNode* >& aListOfNodes = *llIt;
4050     list< const SMDS_MeshNode* >::iterator lIt = aListOfNodes.begin();;
4051     SMESH::long_array& aGroup = (*GroupsOfNodes)[ i ];
4052     aGroup.length( aListOfNodes.size() );
4053     for ( int j = 0; lIt != aListOfNodes.end(); lIt++, j++ )
4054       aGroup[ j ] = (*lIt)->GetID();
4055   }
4056 }
4057
4058 //=======================================================================
4059 //function : FindCoincidentNodes
4060 //purpose  :
4061 //=======================================================================
4062
4063 void SMESH_MeshEditor_i::
4064 FindCoincidentNodes (CORBA::Double                  Tolerance,
4065                      SMESH::array_of_long_array_out GroupsOfNodes,
4066                      CORBA::Boolean                 SeparateCornersAndMedium)
4067   throw (SALOME::SALOME_Exception)
4068 {
4069   SMESH_TRY;
4070   initData();
4071
4072   TIDSortedNodeSet nodes; // no input nodes
4073   findCoincidentNodes( nodes, Tolerance, GroupsOfNodes, SeparateCornersAndMedium );
4074
4075   TPythonDump() << "coincident_nodes = " << this << ".FindCoincidentNodes( "
4076                 << Tolerance << ", "
4077                 << SeparateCornersAndMedium << " )";
4078
4079   SMESH_CATCH( SMESH::throwCorbaException );
4080 }
4081
4082 //=======================================================================
4083 //function : FindCoincidentNodesOnPart
4084 //purpose  :
4085 //=======================================================================
4086
4087 void SMESH_MeshEditor_i::
4088 FindCoincidentNodesOnPart(SMESH::SMESH_IDSource_ptr      theObject,
4089                           CORBA::Double                  Tolerance,
4090                           SMESH::array_of_long_array_out GroupsOfNodes,
4091                           CORBA::Boolean                 SeparateCornersAndMedium)
4092   throw (SALOME::SALOME_Exception)
4093 {
4094   SMESH_TRY;
4095   initData();
4096
4097   TIDSortedNodeSet nodes;
4098   idSourceToNodeSet( theObject, getMeshDS(), nodes );
4099
4100   findCoincidentNodes( nodes, Tolerance, GroupsOfNodes, SeparateCornersAndMedium );
4101
4102   TPythonDump() << "coincident_nodes_on_part = " << this << ".FindCoincidentNodesOnPart( "
4103                 << theObject <<", "
4104                 << Tolerance << ", "
4105                 << SeparateCornersAndMedium << " )";
4106
4107   SMESH_CATCH( SMESH::throwCorbaException );
4108 }
4109
4110 //================================================================================
4111 /*!
4112  * \brief Finds nodes coinsident with Tolerance within Object excluding nodes within
4113  *        ExceptSubMeshOrGroups
4114  */
4115 //================================================================================
4116
4117 void SMESH_MeshEditor_i::
4118 FindCoincidentNodesOnPartBut(SMESH::SMESH_IDSource_ptr      theObject,
4119                              CORBA::Double                  theTolerance,
4120                              SMESH::array_of_long_array_out theGroupsOfNodes,
4121                              const SMESH::ListOfIDSources&  theExceptSubMeshOrGroups,
4122                              CORBA::Boolean                 theSeparateCornersAndMedium)
4123   throw (SALOME::SALOME_Exception)
4124 {
4125   SMESH_TRY;
4126   initData();
4127
4128   TIDSortedNodeSet nodes;
4129   idSourceToNodeSet( theObject, getMeshDS(), nodes );
4130
4131   for ( CORBA::ULong i = 0; i < theExceptSubMeshOrGroups.length(); ++i )
4132   {
4133     SMDS_ElemIteratorPtr nodeIt = myMesh_i->GetElements( theExceptSubMeshOrGroups[i],
4134                                                          SMESH::NODE );
4135     while ( nodeIt->more() )
4136       nodes.erase( cast2Node( nodeIt->next() ));
4137   }
4138   findCoincidentNodes( nodes, theTolerance, theGroupsOfNodes, theSeparateCornersAndMedium );
4139
4140   TPythonDump() << "coincident_nodes_on_part = " << this << ".FindCoincidentNodesOnPartBut( "
4141                 << theObject<<", "
4142                 << theTolerance << ", "
4143                 << theExceptSubMeshOrGroups << ", "
4144                 << theSeparateCornersAndMedium << " )";
4145
4146   SMESH_CATCH( SMESH::throwCorbaException );
4147 }
4148
4149 //=======================================================================
4150 //function : MergeNodes
4151 //purpose  :
4152 //=======================================================================
4153
4154 void SMESH_MeshEditor_i::MergeNodes (const SMESH::array_of_long_array& GroupsOfNodes,
4155                                      const SMESH::ListOfIDSources&     NodesToKeep)
4156   throw (SALOME::SALOME_Exception)
4157 {
4158   SMESH_TRY;
4159   initData();
4160
4161   SMESHDS_Mesh* aMesh = getMeshDS();
4162
4163   TPythonDump aTPythonDump;
4164   aTPythonDump << this << ".MergeNodes([";
4165
4166   TIDSortedNodeSet setOfNodesToKeep;
4167   for ( CORBA::ULong i = 0; i < NodesToKeep.length(); ++i )
4168   {
4169     prepareIdSource( NodesToKeep[i] );
4170     SMDS_ElemIteratorPtr nodeIt = myMesh_i->GetElements( NodesToKeep[i], SMESH::NODE );
4171     while ( nodeIt->more() )
4172       setOfNodesToKeep.insert( setOfNodesToKeep.end(), cast2Node( nodeIt->next() ));
4173   }
4174
4175   ::SMESH_MeshEditor::TListOfListOfNodes aListOfListOfNodes;
4176   for ( CORBA::ULong i = 0; i < GroupsOfNodes.length(); i++ )
4177   {
4178     const SMESH::long_array& aNodeGroup = GroupsOfNodes[ i ];
4179     aListOfListOfNodes.push_back( list< const SMDS_MeshNode* >() );
4180     list< const SMDS_MeshNode* >& aListOfNodes = aListOfListOfNodes.back();
4181     for ( CORBA::ULong j = 0; j < aNodeGroup.length(); j++ )
4182     {
4183       CORBA::Long index = aNodeGroup[ j ];
4184       if ( const SMDS_MeshNode * node = aMesh->FindNode( index ))
4185       {
4186         if ( setOfNodesToKeep.count( node ))
4187           aListOfNodes.push_front( node );
4188         else
4189           aListOfNodes.push_back( node );
4190       }
4191     }
4192     if ( aListOfNodes.size() < 2 )
4193       aListOfListOfNodes.pop_back();
4194
4195     if ( i > 0 ) aTPythonDump << ", ";
4196     aTPythonDump << aNodeGroup;
4197   }
4198
4199   getEditor().MergeNodes( aListOfListOfNodes );
4200
4201   aTPythonDump << "], " << NodesToKeep << ")";
4202
4203   declareMeshModified( /*isReComputeSafe=*/false );
4204
4205   SMESH_CATCH( SMESH::throwCorbaException );
4206 }
4207
4208 //=======================================================================
4209 //function : FindEqualElements
4210 //purpose  :
4211 //=======================================================================
4212
4213 void SMESH_MeshEditor_i::FindEqualElements(SMESH::SMESH_IDSource_ptr      theObject,
4214                                            SMESH::array_of_long_array_out GroupsOfElementsID)
4215   throw (SALOME::SALOME_Exception)
4216 {
4217   SMESH_TRY;
4218   initData();
4219
4220   SMESH::SMESH_GroupBase_var group = SMESH::SMESH_GroupBase::_narrow(theObject);
4221   if ( !(!group->_is_nil() && group->GetType() == SMESH::NODE) )
4222   {
4223     TIDSortedElemSet elems;
4224     idSourceToSet( theObject, getMeshDS(), elems, SMDSAbs_All, /*emptyIfIsMesh=*/true);
4225
4226     ::SMESH_MeshEditor::TListOfListOfElementsID aListOfListOfElementsID;
4227     getEditor().FindEqualElements( elems, aListOfListOfElementsID );
4228
4229     GroupsOfElementsID = new SMESH::array_of_long_array;
4230     GroupsOfElementsID->length( aListOfListOfElementsID.size() );
4231
4232     ::SMESH_MeshEditor::TListOfListOfElementsID::iterator arraysIt =
4233         aListOfListOfElementsID.begin();
4234     for (CORBA::Long j = 0; arraysIt != aListOfListOfElementsID.end(); ++arraysIt, ++j)
4235     {
4236       SMESH::long_array& aGroup = (*GroupsOfElementsID)[ j ];
4237       list<int>&      listOfIDs = *arraysIt;
4238       aGroup.length( listOfIDs.size() );
4239       list<int>::iterator idIt = listOfIDs.begin();
4240       for (int k = 0; idIt != listOfIDs.end(); ++idIt, ++k )
4241         aGroup[ k ] = *idIt;
4242     }
4243
4244     TPythonDump() << "equal_elements = " << this << ".FindEqualElements( "
4245                   <<theObject<<" )";
4246   }
4247
4248   SMESH_CATCH( SMESH::throwCorbaException );
4249 }
4250
4251 //=======================================================================
4252 //function : MergeElements
4253 //purpose  :
4254 //=======================================================================
4255
4256 void SMESH_MeshEditor_i::MergeElements(const SMESH::array_of_long_array& GroupsOfElementsID)
4257   throw (SALOME::SALOME_Exception)
4258 {
4259   SMESH_TRY;
4260   initData();
4261
4262   TPythonDump aTPythonDump;
4263   aTPythonDump << this << ".MergeElements( [";
4264
4265   ::SMESH_MeshEditor::TListOfListOfElementsID aListOfListOfElementsID;
4266
4267   for ( CORBA::ULong i = 0; i < GroupsOfElementsID.length(); i++ ) {
4268     const SMESH::long_array& anElemsIDGroup = GroupsOfElementsID[ i ];
4269     aListOfListOfElementsID.push_back( list< int >() );
4270     list< int >& aListOfElemsID = aListOfListOfElementsID.back();
4271     for ( CORBA::ULong j = 0; j < anElemsIDGroup.length(); j++ ) {
4272       CORBA::Long id = anElemsIDGroup[ j ];
4273       aListOfElemsID.push_back( id );
4274     }
4275     if ( aListOfElemsID.size() < 2 )
4276       aListOfListOfElementsID.pop_back();
4277     if ( i > 0 ) aTPythonDump << ", ";
4278     aTPythonDump << anElemsIDGroup;
4279   }
4280
4281   getEditor().MergeElements(aListOfListOfElementsID);
4282
4283   declareMeshModified( /*isReComputeSafe=*/true );
4284
4285   aTPythonDump << "] )";
4286
4287   SMESH_CATCH( SMESH::throwCorbaException );
4288 }
4289
4290 //=======================================================================
4291 //function : MergeEqualElements
4292 //purpose  :
4293 //=======================================================================
4294
4295 void SMESH_MeshEditor_i::MergeEqualElements()
4296   throw (SALOME::SALOME_Exception)
4297 {
4298   SMESH_TRY;
4299   initData();
4300
4301   getEditor().MergeEqualElements();
4302
4303   declareMeshModified( /*isReComputeSafe=*/true );
4304
4305   TPythonDump() << this << ".MergeEqualElements()";
4306
4307   SMESH_CATCH( SMESH::throwCorbaException );
4308 }
4309
4310 //=============================================================================
4311 /*!
4312  * Move the node to a given point
4313  */
4314 //=============================================================================
4315
4316 CORBA::Boolean SMESH_MeshEditor_i::MoveNode(CORBA::Long   NodeID,
4317                                             CORBA::Double x,
4318                                             CORBA::Double y,
4319                                             CORBA::Double z)
4320   throw (SALOME::SALOME_Exception)
4321 {
4322   SMESH_TRY;
4323   initData(/*deleteSearchers=*/false);
4324
4325   const SMDS_MeshNode * node = getMeshDS()->FindNode( NodeID );
4326   if ( !node )
4327     return false;
4328
4329   if ( theNodeSearcher )
4330     theSearchersDeleter.Set( myMesh ); // remove theNodeSearcher if mesh is other
4331
4332   if ( myIsPreviewMode ) // make preview data
4333   {
4334     // in a preview mesh, make edges linked to a node
4335     TPreviewMesh& tmpMesh = *getPreviewMesh();
4336     TIDSortedElemSet linkedNodes;
4337     ::SMESH_MeshEditor::GetLinkedNodes( node, linkedNodes );
4338     TIDSortedElemSet::iterator nIt = linkedNodes.begin();
4339     SMDS_MeshNode *nodeCpy1 = tmpMesh.Copy(node);
4340     for ( ; nIt != linkedNodes.end(); ++nIt )
4341     {
4342       SMDS_MeshNode *nodeCpy2 = tmpMesh.Copy ( cast2Node( *nIt ));
4343       tmpMesh.GetMeshDS()->AddEdge(nodeCpy1, nodeCpy2);
4344     }
4345     // move copied node
4346     if ( nodeCpy1 )
4347       tmpMesh.GetMeshDS()->MoveNode(nodeCpy1, x, y, z);
4348     // fill preview data
4349   }
4350   else if ( theNodeSearcher ) // move node and update theNodeSearcher data accordingly
4351     theNodeSearcher->MoveNode(node, gp_Pnt( x,y,z ));
4352   else
4353     getMeshDS()->MoveNode(node, x, y, z);
4354
4355   if ( !myIsPreviewMode )
4356   {
4357     // Update Python script
4358     TPythonDump() << "isDone = " << this << ".MoveNode( "
4359                   << NodeID << ", " << TVar(x) << ", " << TVar(y) << ", " << TVar(z) << " )";
4360     declareMeshModified( /*isReComputeSafe=*/false );
4361   }
4362
4363   SMESH_CATCH( SMESH::throwCorbaException );
4364
4365   return true;
4366 }
4367
4368 //================================================================================
4369 /*!
4370  * \brief Return ID of node closest to a given point
4371  */
4372 //================================================================================
4373
4374 CORBA::Long SMESH_MeshEditor_i::FindNodeClosestTo(CORBA::Double x,
4375                                                   CORBA::Double y,
4376                                                   CORBA::Double z)
4377   throw (SALOME::SALOME_Exception)
4378 {
4379   SMESH_TRY;
4380   theSearchersDeleter.Set( myMesh ); // remove theNodeSearcher if mesh is other
4381
4382   if ( !theNodeSearcher ) {
4383     theNodeSearcher = SMESH_MeshAlgos::GetNodeSearcher( *getMeshDS() );
4384   }
4385   gp_Pnt p( x,y,z );
4386   if ( const SMDS_MeshNode* node = theNodeSearcher->FindClosestTo( p ))
4387     return node->GetID();
4388
4389   SMESH_CATCH( SMESH::throwCorbaException );
4390   return 0;
4391 }
4392
4393 //================================================================================
4394 /*!
4395  * \brief If the given ID is a valid node ID (nodeID > 0), just move this node, else
4396  * move the node closest to the point to point's location and return ID of the node
4397  */
4398 //================================================================================
4399
4400 CORBA::Long SMESH_MeshEditor_i::MoveClosestNodeToPoint(CORBA::Double x,
4401                                                        CORBA::Double y,
4402                                                        CORBA::Double z,
4403                                                        CORBA::Long   theNodeID)
4404   throw (SALOME::SALOME_Exception)
4405 {
4406   SMESH_TRY;
4407   // We keep theNodeSearcher until any mesh modification:
4408   // 1) initData() deletes theNodeSearcher at any edition,
4409   // 2) TSearchersDeleter - at any mesh compute event and mesh change
4410
4411   initData(/*deleteSearchers=*/false);
4412
4413   theSearchersDeleter.Set( myMesh ); // remove theNodeSearcher if mesh is other
4414
4415   int nodeID = theNodeID;
4416   const SMDS_MeshNode* node = getMeshDS()->FindNode( nodeID );
4417   if ( !node ) // preview moving node
4418   {
4419     if ( !theNodeSearcher ) {
4420       theNodeSearcher = SMESH_MeshAlgos::GetNodeSearcher( *getMeshDS() );
4421     }
4422     gp_Pnt p( x,y,z );
4423     node = theNodeSearcher->FindClosestTo( p );
4424   }
4425   if ( node ) {
4426     nodeID = node->GetID();
4427     if ( myIsPreviewMode ) // make preview data
4428     {
4429       // in a preview mesh, make edges linked to a node
4430       TPreviewMesh tmpMesh = *getPreviewMesh();
4431       TIDSortedElemSet linkedNodes;
4432       ::SMESH_MeshEditor::GetLinkedNodes( node, linkedNodes );
4433       TIDSortedElemSet::iterator nIt = linkedNodes.begin();
4434       for ( ; nIt != linkedNodes.end(); ++nIt )
4435       {
4436         SMDS_LinearEdge edge( node, cast2Node( *nIt ));
4437         tmpMesh.Copy( &edge );
4438       }
4439       // move copied node
4440       node = tmpMesh.GetMeshDS()->FindNode( nodeID );
4441       if ( node )
4442         tmpMesh.GetMeshDS()->MoveNode(node, x, y, z);
4443       // fill preview data
4444     }
4445     else if ( theNodeSearcher ) // move node and update theNodeSearcher data accordingly
4446     {
4447       theNodeSearcher->MoveNode(node, gp_Pnt( x,y,z ));
4448     }
4449     else
4450     {
4451       getMeshDS()->MoveNode(node, x, y, z);
4452     }
4453   }
4454
4455   if ( !myIsPreviewMode )
4456   {
4457     TPythonDump() << "nodeID = " << this
4458                   << ".MoveClosestNodeToPoint( "<< x << ", " << y << ", " << z
4459                   << ", " << nodeID << " )";
4460
4461     declareMeshModified( /*isReComputeSafe=*/false );
4462   }
4463
4464   return nodeID;
4465
4466   SMESH_CATCH( SMESH::throwCorbaException );
4467   return 0;
4468 }
4469
4470 //=======================================================================
4471 /*!
4472  * Return elements of given type where the given point is IN or ON.
4473  *
4474  * 'ALL' type means elements of any type excluding nodes
4475  */
4476 //=======================================================================
4477
4478 SMESH::long_array* SMESH_MeshEditor_i::FindElementsByPoint(CORBA::Double      x,
4479                                                            CORBA::Double      y,
4480                                                            CORBA::Double      z,
4481                                                            SMESH::ElementType type)
4482   throw (SALOME::SALOME_Exception)
4483 {
4484   SMESH_TRY;
4485   SMESH::long_array_var res = new SMESH::long_array;
4486   vector< const SMDS_MeshElement* > foundElems;
4487
4488   theSearchersDeleter.Set( myMesh );
4489   if ( !theElementSearcher ) {
4490     theElementSearcher = SMESH_MeshAlgos::GetElementSearcher( *getMeshDS() );
4491   }
4492   theElementSearcher->FindElementsByPoint( gp_Pnt( x,y,z ),
4493                                            SMDSAbs_ElementType( type ),
4494                                            foundElems);
4495   res->length( foundElems.size() );
4496   for ( size_t i = 0; i < foundElems.size(); ++i )
4497     res[i] = foundElems[i]->GetID();
4498
4499   return res._retn();
4500
4501   SMESH_CATCH( SMESH::throwCorbaException );
4502   return 0;
4503 }
4504
4505 //=======================================================================
4506 //function : FindAmongElementsByPoint
4507 //purpose  : Searching among the given elements, return elements of given type 
4508 //           where the given point is IN or ON.
4509 //           'ALL' type means elements of any type excluding nodes
4510 //=======================================================================
4511
4512 SMESH::long_array*
4513 SMESH_MeshEditor_i::FindAmongElementsByPoint(SMESH::SMESH_IDSource_ptr elementIDs,
4514                                              CORBA::Double             x,
4515                                              CORBA::Double             y,
4516                                              CORBA::Double             z,
4517                                              SMESH::ElementType        type)
4518   throw (SALOME::SALOME_Exception)
4519 {
4520   SMESH_TRY;
4521   SMESH::long_array_var res = new SMESH::long_array;
4522
4523   if ( type != SMESH::NODE )
4524   {
4525     SMESH::array_of_ElementType_var types = elementIDs->GetTypes();
4526     if ( types->length() == 1 && // a part contains only nodes or 0D elements
4527          ( types[0] == SMESH::NODE || types[0] == SMESH::ELEM0D || types[0] == SMESH::BALL) &&
4528          type != types[0] ) // but search of elements of dim > 0
4529       return res._retn();
4530   }
4531   if ( SMESH::DownCast<SMESH_Mesh_i*>( elementIDs )) // elementIDs is the whole mesh 
4532     return FindElementsByPoint( x,y,z, type );
4533
4534   TIDSortedElemSet elements; // elems should live until FindElementsByPoint() finishes
4535
4536   theSearchersDeleter.Set( myMesh, getPartIOR( elementIDs, type ));
4537   if ( !theElementSearcher )
4538   {
4539     // create a searcher from elementIDs
4540     SMESH::SMESH_Mesh_var mesh = elementIDs->GetMesh();
4541     SMESHDS_Mesh* meshDS = SMESH::DownCast<SMESH_Mesh_i*>( mesh )->GetImpl().GetMeshDS();
4542
4543     if ( !idSourceToSet( elementIDs, meshDS, elements,
4544                          ( type == SMESH::NODE ? SMDSAbs_All : (SMDSAbs_ElementType) type ),
4545                          /*emptyIfIsMesh=*/true))
4546       return res._retn();
4547
4548     typedef SMDS_SetIterator<const SMDS_MeshElement*, TIDSortedElemSet::const_iterator > TIter;
4549     SMDS_ElemIteratorPtr elemsIt( new TIter( elements.begin(), elements.end() ));
4550
4551     theElementSearcher = SMESH_MeshAlgos::GetElementSearcher( *getMeshDS(), elemsIt );
4552   }
4553
4554   vector< const SMDS_MeshElement* > foundElems;
4555
4556   theElementSearcher->FindElementsByPoint( gp_Pnt( x,y,z ),
4557                                            SMDSAbs_ElementType( type ),
4558                                            foundElems);
4559   res->length( foundElems.size() );
4560   for ( size_t i = 0; i < foundElems.size(); ++i )
4561     res[i] = foundElems[i]->GetID();
4562
4563   return res._retn();
4564
4565   SMESH_CATCH( SMESH::throwCorbaException );
4566   return 0;
4567 }
4568
4569 //=======================================================================
4570 //function : GetPointState
4571 //purpose  : Return point state in a closed 2D mesh in terms of TopAbs_State enumeration.
4572 //           TopAbs_UNKNOWN state means that either mesh is wrong or the analysis fails.
4573 //=======================================================================
4574
4575 CORBA::Short SMESH_MeshEditor_i::GetPointState(CORBA::Double x,
4576                                                CORBA::Double y,
4577                                                CORBA::Double z)
4578   throw (SALOME::SALOME_Exception)
4579 {
4580   SMESH_TRY;
4581   theSearchersDeleter.Set( myMesh );
4582   if ( !theElementSearcher ) {
4583     theElementSearcher = SMESH_MeshAlgos::GetElementSearcher( *getMeshDS() );
4584   }
4585   return CORBA::Short( theElementSearcher->GetPointState( gp_Pnt( x,y,z )));
4586
4587   SMESH_CATCH( SMESH::throwCorbaException );
4588   return 0;
4589 }
4590
4591 //=======================================================================
4592 //function : convError
4593 //purpose  :
4594 //=======================================================================
4595
4596 #define RETCASE(enm) case ::SMESH_MeshEditor::enm: return SMESH::SMESH_MeshEditor::enm;
4597
4598 static SMESH::SMESH_MeshEditor::Sew_Error convError( const::SMESH_MeshEditor::Sew_Error e )
4599 {
4600   switch ( e ) {
4601     RETCASE( SEW_OK );
4602     RETCASE( SEW_BORDER1_NOT_FOUND );
4603     RETCASE( SEW_BORDER2_NOT_FOUND );
4604     RETCASE( SEW_BOTH_BORDERS_NOT_FOUND );
4605     RETCASE( SEW_BAD_SIDE_NODES );
4606     RETCASE( SEW_VOLUMES_TO_SPLIT );
4607     RETCASE( SEW_DIFF_NB_OF_ELEMENTS );
4608     RETCASE( SEW_TOPO_DIFF_SETS_OF_ELEMENTS );
4609     RETCASE( SEW_BAD_SIDE1_NODES );
4610     RETCASE( SEW_BAD_SIDE2_NODES );
4611     RETCASE( SEW_INTERNAL_ERROR );
4612   }
4613   return SMESH::SMESH_MeshEditor::SEW_OK;
4614 }
4615
4616 //=======================================================================
4617 /*!
4618  * Returns groups of FreeBorder's coincident within the given tolerance.
4619  * If the tolerance <= 0.0 then one tenth of an average size of elements adjacent
4620  * to free borders being compared is used.
4621  */
4622 //=======================================================================
4623
4624 SMESH::CoincidentFreeBorders*
4625 SMESH_MeshEditor_i::FindCoincidentFreeBorders(CORBA::Double tolerance)
4626 {
4627   SMESH::CoincidentFreeBorders_var aCFB = new SMESH::CoincidentFreeBorders;
4628
4629   SMESH_TRY;
4630
4631   SMESH_MeshAlgos::CoincidentFreeBorders cfb;
4632   SMESH_MeshAlgos::FindCoincidentFreeBorders( *getMeshDS(), tolerance, cfb );
4633
4634   // copy free borders
4635   aCFB->borders.length( cfb._borders.size() );
4636   for ( size_t i = 0; i < cfb._borders.size(); ++i )
4637   {
4638     SMESH_MeshAlgos::TFreeBorder& nodes = cfb._borders[i];
4639     SMESH::FreeBorder&             aBRD = aCFB->borders[i];
4640     aBRD.nodeIDs.length( nodes.size() );
4641     for ( size_t iN = 0; iN < nodes.size(); ++iN )
4642       aBRD.nodeIDs[ iN ] = nodes[ iN ]->GetID();
4643   }
4644
4645   // copy coincident parts
4646   aCFB->coincidentGroups.length( cfb._coincidentGroups.size() );
4647   for ( size_t i = 0; i < cfb._coincidentGroups.size(); ++i )
4648   {
4649     SMESH_MeshAlgos::TCoincidentGroup& grp = cfb._coincidentGroups[i];
4650     SMESH::FreeBordersGroup&          aGRP = aCFB->coincidentGroups[i];
4651     aGRP.length( grp.size() );
4652     for ( size_t iP = 0; iP < grp.size(); ++iP )
4653     {
4654       SMESH_MeshAlgos::TFreeBorderPart& part = grp[ iP ];
4655       SMESH::FreeBorderPart&           aPART = aGRP[ iP ];
4656       aPART.border   = part._border;
4657       aPART.node1    = part._node1;
4658       aPART.node2    = part._node2;
4659       aPART.nodeLast = part._nodeLast;
4660     }
4661   }
4662   SMESH_CATCH( SMESH::doNothing );
4663
4664   TPythonDump() << "CoincidentFreeBorders = "
4665                 << this << ".FindCoincidentFreeBorders( " << tolerance << " )";
4666
4667   return aCFB._retn();
4668 }
4669
4670 //=======================================================================
4671 /*!
4672  * Sew FreeBorder's of each group
4673  */
4674 //=======================================================================
4675
4676 CORBA::Short SMESH_MeshEditor_i::
4677 SewCoincidentFreeBorders(const SMESH::CoincidentFreeBorders& freeBorders,
4678                          CORBA::Boolean                      createPolygons,
4679                          CORBA::Boolean                      createPolyhedra)
4680   throw (SALOME::SALOME_Exception)
4681 {
4682   CORBA::Short nbSewed = 0;
4683
4684   SMESH_MeshAlgos::TFreeBorderVec groups;
4685   SMESH_MeshAlgos::TFreeBorder    borderNodes; // triples of nodes for every FreeBorderPart
4686
4687   // check the input and collect nodes
4688   for ( CORBA::ULong i = 0; i < freeBorders.coincidentGroups.length(); ++i )
4689   {
4690     borderNodes.clear();
4691     const SMESH::FreeBordersGroup& aGRP = freeBorders.coincidentGroups[ i ];
4692     for ( CORBA::ULong iP = 0; iP < aGRP.length(); ++iP )
4693     {
4694       const SMESH::FreeBorderPart& aPART = aGRP[ iP ];
4695       if ( aPART.border < 0 || aPART.border >= (int) freeBorders.borders.length() )
4696         THROW_SALOME_CORBA_EXCEPTION("Invalid FreeBorderPart::border index", SALOME::BAD_PARAM);
4697
4698       const SMESH::FreeBorder& aBRD = freeBorders.borders[ aPART.border ];
4699
4700       if ( aPART.node1 < 0 || aPART.node1 > (int) aBRD.nodeIDs.length() )
4701         THROW_SALOME_CORBA_EXCEPTION("Invalid FreeBorderPart::node1", SALOME::BAD_PARAM);
4702       if ( aPART.node2 < 0 || aPART.node2 > (int) aBRD.nodeIDs.length() )
4703         THROW_SALOME_CORBA_EXCEPTION("Invalid FreeBorderPart::node2", SALOME::BAD_PARAM);
4704       if ( aPART.nodeLast < 0 || aPART.nodeLast > (int) aBRD.nodeIDs.length() )
4705         THROW_SALOME_CORBA_EXCEPTION("Invalid FreeBorderPart::nodeLast", SALOME::BAD_PARAM);
4706
4707       // do not keep these nodes for further sewing as nodes can be removed by the sewing
4708       const SMDS_MeshNode* n1 = getMeshDS()->FindNode( aBRD.nodeIDs[ aPART.node1    ]);
4709       const SMDS_MeshNode* n2 = getMeshDS()->FindNode( aBRD.nodeIDs[ aPART.node2    ]);
4710       const SMDS_MeshNode* n3 = getMeshDS()->FindNode( aBRD.nodeIDs[ aPART.nodeLast ]);
4711       if ( !n1)
4712         THROW_SALOME_CORBA_EXCEPTION("Nonexistent FreeBorderPart::node1", SALOME::BAD_PARAM);
4713       if ( !n2 )
4714         THROW_SALOME_CORBA_EXCEPTION("Nonexistent FreeBorderPart::node2", SALOME::BAD_PARAM);
4715       if ( !n3 )
4716         THROW_SALOME_CORBA_EXCEPTION("Nonexistent FreeBorderPart::nodeLast", SALOME::BAD_PARAM);
4717
4718       borderNodes.push_back( n1 );
4719       borderNodes.push_back( n2 );
4720       borderNodes.push_back( n3 );
4721     }
4722     groups.push_back( borderNodes );
4723   }
4724
4725   // SewFreeBorder() can merge nodes, thus nodes stored in 'groups' can become dead;
4726   // to get nodes that replace other nodes during merge we create 0D elements
4727   // on each node and MergeNodes() will replace underlying nodes of 0D elements by
4728   // new ones.
4729
4730   vector< const SMDS_MeshElement* > tmp0Delems;
4731   for ( size_t i = 0; i < groups.size(); ++i )
4732   {
4733     SMESH_MeshAlgos::TFreeBorder& nodes = groups[i];
4734     for ( size_t iN = 0; iN < nodes.size(); ++iN )
4735     {
4736       SMDS_ElemIteratorPtr it0D = nodes[iN]->GetInverseElementIterator(SMDSAbs_0DElement);
4737       if ( it0D->more() )
4738         tmp0Delems.push_back( it0D->next() );
4739       else
4740         tmp0Delems.push_back( getMeshDS()->Add0DElement( nodes[iN] ));
4741     }
4742   }
4743
4744   // cout << endl << "INIT" << endl;
4745   // for ( size_t i = 0; i < tmp0Delems.size(); ++i )
4746   // {
4747   //   cout << i << " ";
4748   //   if ( i % 3 == 0 ) cout << "^ ";
4749   //   tmp0Delems[i]->GetNode(0)->Print( cout );
4750   // }
4751
4752   SMESH_TRY;
4753
4754   ::SMESH_MeshEditor::Sew_Error res, ok = ::SMESH_MeshEditor::SEW_OK;
4755   int i0D = 0;
4756   for ( size_t i = 0; i < groups.size(); ++i )
4757   {
4758     bool isBordToBord = true;
4759     bool   groupSewed = false;
4760     SMESH_MeshAlgos::TFreeBorder& nodes = groups[i];
4761     for ( size_t iN = 3; iN+2 < nodes.size(); iN += 3 )
4762     {
4763       const SMDS_MeshNode* n0 = tmp0Delems[ i0D + 0 ]->GetNode( 0 );
4764       const SMDS_MeshNode* n1 = tmp0Delems[ i0D + 1 ]->GetNode( 0 );
4765       const SMDS_MeshNode* n2 = tmp0Delems[ i0D + 2 ]->GetNode( 0 );
4766
4767       const SMDS_MeshNode* n3 = tmp0Delems[ i0D + 0 + iN ]->GetNode( 0 );
4768       const SMDS_MeshNode* n4 = tmp0Delems[ i0D + 1 + iN ]->GetNode( 0 );
4769       const SMDS_MeshNode* n5 = tmp0Delems[ i0D + 2 + iN ]->GetNode( 0 );
4770
4771       if ( !n0 || !n1 || !n2 || !n3 || !n4 || !n5 )
4772         continue;
4773
4774       // TIDSortedElemSet emptySet, avoidSet;
4775       // if ( !SMESH_MeshAlgos::FindFaceInSet( n0, n1, emptySet, avoidSet))
4776       // {
4777       //   cout << "WRONG 2nd 1" << endl;
4778       //   n0->Print( cout );
4779       //   n1->Print( cout );
4780       // }
4781       // if ( !SMESH_MeshAlgos::FindFaceInSet( n3, n4, emptySet, avoidSet))
4782       // {
4783       //   cout << "WRONG 2nd 2" << endl;
4784       //   n3->Print( cout );
4785       //   n4->Print( cout );
4786       // }
4787
4788       if ( !isBordToBord )
4789       {
4790         n1 = n2; // at border-to-side sewing only last side node (n1) is needed
4791         n2 = 0;  //  and n2 is not used
4792       }
4793       // 1st border moves to 2nd
4794       res = getEditor().SewFreeBorder( n3, n4, n5 ,// 1st
4795                                        n0 ,n1 ,n2 ,// 2nd
4796                                        /*2ndIsFreeBorder=*/ isBordToBord,
4797                                        createPolygons, createPolyhedra);
4798       groupSewed = ( res == ok );
4799
4800       isBordToBord = false;
4801       // cout << endl << "SEWED GROUP " << i << " PART " << iN / 3 << endl;
4802       // for ( size_t t = 0; t < tmp0Delems.size(); ++t )
4803       // {
4804       //   cout << t << " ";
4805       //   if ( t % 3 == 0 ) cout << "^ ";
4806       //   tmp0Delems[t]->GetNode(0)->Print( cout );
4807       // }
4808     }
4809     i0D += nodes.size();
4810     nbSewed += groupSewed;
4811   }
4812
4813   TPythonDump() << "nbSewed = " << this << ".SewCoincidentFreeBorders( "
4814                 << freeBorders     << ", "
4815                 << createPolygons  << ", "
4816                 << createPolyhedra << " )";
4817
4818   SMESH_CATCH( SMESH::doNothing );
4819
4820   declareMeshModified( /*isReComputeSafe=*/false );
4821
4822   // remove tmp 0D elements
4823   SMESH_TRY;
4824   set< const SMDS_MeshElement* > removed0D;
4825   for ( size_t i = 0; i < tmp0Delems.size(); ++i )
4826   {
4827     if ( removed0D.insert( tmp0Delems[i] ).second )
4828       getMeshDS()->RemoveFreeElement( tmp0Delems[i], /*sm=*/0, /*fromGroups=*/false );
4829   }
4830   SMESH_CATCH( SMESH::throwCorbaException );
4831
4832   return nbSewed;
4833 }
4834
4835 //=======================================================================
4836 //function : SewFreeBorders
4837 //purpose  :
4838 //=======================================================================
4839
4840 SMESH::SMESH_MeshEditor::Sew_Error
4841 SMESH_MeshEditor_i::SewFreeBorders(CORBA::Long FirstNodeID1,
4842                                    CORBA::Long SecondNodeID1,
4843                                    CORBA::Long LastNodeID1,
4844                                    CORBA::Long FirstNodeID2,
4845                                    CORBA::Long SecondNodeID2,
4846                                    CORBA::Long LastNodeID2,
4847                                    CORBA::Boolean CreatePolygons,
4848                                    CORBA::Boolean CreatePolyedrs)
4849   throw (SALOME::SALOME_Exception)
4850 {
4851   SMESH_TRY;
4852   initData();
4853
4854   SMESHDS_Mesh* aMesh = getMeshDS();
4855
4856   const SMDS_MeshNode* aBorderFirstNode  = aMesh->FindNode( FirstNodeID1  );
4857   const SMDS_MeshNode* aBorderSecondNode = aMesh->FindNode( SecondNodeID1 );
4858   const SMDS_MeshNode* aBorderLastNode   = aMesh->FindNode( LastNodeID1   );
4859   const SMDS_MeshNode* aSide2FirstNode   = aMesh->FindNode( FirstNodeID2  );
4860   const SMDS_MeshNode* aSide2SecondNode  = aMesh->FindNode( SecondNodeID2 );
4861   const SMDS_MeshNode* aSide2ThirdNode   = aMesh->FindNode( LastNodeID2   );
4862
4863   if (!aBorderFirstNode ||
4864       !aBorderSecondNode||
4865       !aBorderLastNode)
4866     return SMESH::SMESH_MeshEditor::SEW_BORDER1_NOT_FOUND;
4867   if (!aSide2FirstNode  ||
4868       !aSide2SecondNode ||
4869       !aSide2ThirdNode)
4870     return SMESH::SMESH_MeshEditor::SEW_BORDER2_NOT_FOUND;
4871
4872   TPythonDump() << "error = " << this << ".SewFreeBorders( "
4873                 << FirstNodeID1  << ", "
4874                 << SecondNodeID1 << ", "
4875                 << LastNodeID1   << ", "
4876                 << FirstNodeID2  << ", "
4877                 << SecondNodeID2 << ", "
4878                 << LastNodeID2   << ", "
4879                 << CreatePolygons<< ", "
4880                 << CreatePolyedrs<< " )";
4881
4882   SMESH::SMESH_MeshEditor::Sew_Error error =
4883     convError( getEditor().SewFreeBorder (aBorderFirstNode,
4884                                           aBorderSecondNode,
4885                                           aBorderLastNode,
4886                                           aSide2FirstNode,
4887                                           aSide2SecondNode,
4888                                           aSide2ThirdNode,
4889                                           true,
4890                                           CreatePolygons,
4891                                           CreatePolyedrs) );
4892
4893
4894   declareMeshModified( /*isReComputeSafe=*/false );
4895   return error;
4896
4897   SMESH_CATCH( SMESH::throwCorbaException );
4898   return SMESH::SMESH_MeshEditor::Sew_Error(0);
4899 }
4900
4901
4902 //=======================================================================
4903 //function : SewConformFreeBorders
4904 //purpose  :
4905 //=======================================================================
4906
4907 SMESH::SMESH_MeshEditor::Sew_Error
4908 SMESH_MeshEditor_i::SewConformFreeBorders(CORBA::Long FirstNodeID1,
4909                                           CORBA::Long SecondNodeID1,
4910                                           CORBA::Long LastNodeID1,
4911                                           CORBA::Long FirstNodeID2,
4912                                           CORBA::Long SecondNodeID2)
4913   throw (SALOME::SALOME_Exception)
4914 {
4915   SMESH_TRY;
4916   initData();
4917
4918   SMESHDS_Mesh* aMesh = getMeshDS();
4919
4920   const SMDS_MeshNode* aBorderFirstNode  = aMesh->FindNode( FirstNodeID1  );
4921   const SMDS_MeshNode* aBorderSecondNode = aMesh->FindNode( SecondNodeID1 );
4922   const SMDS_MeshNode* aBorderLastNode   = aMesh->FindNode( LastNodeID1   );
4923   const SMDS_MeshNode* aSide2FirstNode   = aMesh->FindNode( FirstNodeID2  );
4924   const SMDS_MeshNode* aSide2SecondNode  = aMesh->FindNode( SecondNodeID2 );
4925   const SMDS_MeshNode* aSide2ThirdNode   = 0;
4926
4927   if (!aBorderFirstNode ||
4928       !aBorderSecondNode||
4929       !aBorderLastNode )
4930     return SMESH::SMESH_MeshEditor::SEW_BORDER1_NOT_FOUND;
4931   if (!aSide2FirstNode  ||
4932       !aSide2SecondNode)
4933     return SMESH::SMESH_MeshEditor::SEW_BORDER2_NOT_FOUND;
4934
4935   TPythonDump() << "error = " << this << ".SewConformFreeBorders( "
4936                 << FirstNodeID1  << ", "
4937                 << SecondNodeID1 << ", "
4938                 << LastNodeID1   << ", "
4939                 << FirstNodeID2  << ", "
4940                 << SecondNodeID2 << " )";
4941
4942   SMESH::SMESH_MeshEditor::Sew_Error error =
4943     convError( getEditor().SewFreeBorder (aBorderFirstNode,
4944                                           aBorderSecondNode,
4945                                           aBorderLastNode,
4946                                           aSide2FirstNode,
4947                                           aSide2SecondNode,
4948                                           aSide2ThirdNode,
4949                                           true,
4950                                           false, false) );
4951
4952   declareMeshModified( /*isReComputeSafe=*/false );
4953   return error;
4954
4955   SMESH_CATCH( SMESH::throwCorbaException );
4956   return SMESH::SMESH_MeshEditor::Sew_Error(0);
4957 }
4958
4959
4960 //=======================================================================
4961 //function : SewBorderToSide
4962 //purpose  :
4963 //=======================================================================
4964
4965 SMESH::SMESH_MeshEditor::Sew_Error
4966 SMESH_MeshEditor_i::SewBorderToSide(CORBA::Long FirstNodeIDOnFreeBorder,
4967                                     CORBA::Long SecondNodeIDOnFreeBorder,
4968                                     CORBA::Long LastNodeIDOnFreeBorder,
4969                                     CORBA::Long FirstNodeIDOnSide,
4970                                     CORBA::Long LastNodeIDOnSide,
4971                                     CORBA::Boolean CreatePolygons,
4972                                     CORBA::Boolean CreatePolyedrs)
4973   throw (SALOME::SALOME_Exception)
4974 {
4975   SMESH_TRY;
4976   initData();
4977
4978   SMESHDS_Mesh* aMesh = getMeshDS();
4979
4980   const SMDS_MeshNode* aBorderFirstNode  = aMesh->FindNode( FirstNodeIDOnFreeBorder  );
4981   const SMDS_MeshNode* aBorderSecondNode = aMesh->FindNode( SecondNodeIDOnFreeBorder );
4982   const SMDS_MeshNode* aBorderLastNode   = aMesh->FindNode( LastNodeIDOnFreeBorder   );
4983   const SMDS_MeshNode* aSide2FirstNode   = aMesh->FindNode( FirstNodeIDOnSide  );
4984   const SMDS_MeshNode* aSide2SecondNode  = aMesh->FindNode( LastNodeIDOnSide );
4985   const SMDS_MeshNode* aSide2ThirdNode   = 0;
4986
4987   if (!aBorderFirstNode ||
4988       !aBorderSecondNode||
4989       !aBorderLastNode  )
4990     return SMESH::SMESH_MeshEditor::SEW_BORDER1_NOT_FOUND;
4991   if (!aSide2FirstNode  ||
4992       !aSide2SecondNode)
4993     return SMESH::SMESH_MeshEditor::SEW_BAD_SIDE_NODES;
4994
4995   TPythonDump() << "error = " << this << ".SewBorderToSide( "
4996                 << FirstNodeIDOnFreeBorder  << ", "
4997                 << SecondNodeIDOnFreeBorder << ", "
4998                 << LastNodeIDOnFreeBorder   << ", "
4999                 << FirstNodeIDOnSide        << ", "
5000                 << LastNodeIDOnSide         << ", "
5001                 << CreatePolygons           << ", "
5002                 << CreatePolyedrs           << ") ";
5003
5004   SMESH::SMESH_MeshEditor::Sew_Error error =
5005     convError( getEditor().SewFreeBorder (aBorderFirstNode,
5006                                           aBorderSecondNode,
5007                                           aBorderLastNode,
5008                                           aSide2FirstNode,
5009                                           aSide2SecondNode,
5010                                           aSide2ThirdNode,
5011                                           false,
5012                                           CreatePolygons,
5013                                           CreatePolyedrs) );
5014
5015   declareMeshModified( /*isReComputeSafe=*/false );
5016   return error;
5017
5018   SMESH_CATCH( SMESH::throwCorbaException );
5019   return SMESH::SMESH_MeshEditor::Sew_Error(0);
5020 }
5021
5022
5023 //=======================================================================
5024 //function : SewSideElements
5025 //purpose  :
5026 //=======================================================================
5027
5028 SMESH::SMESH_MeshEditor::Sew_Error
5029 SMESH_MeshEditor_i::SewSideElements(const SMESH::long_array& IDsOfSide1Elements,
5030                                     const SMESH::long_array& IDsOfSide2Elements,
5031                                     CORBA::Long NodeID1OfSide1ToMerge,
5032                                     CORBA::Long NodeID1OfSide2ToMerge,
5033                                     CORBA::Long NodeID2OfSide1ToMerge,
5034                                     CORBA::Long NodeID2OfSide2ToMerge)
5035   throw (SALOME::SALOME_Exception)
5036 {
5037   SMESH_TRY;
5038   initData();
5039
5040   SMESHDS_Mesh* aMesh = getMeshDS();
5041
5042   const SMDS_MeshNode* aFirstNode1ToMerge  = aMesh->FindNode( NodeID1OfSide1ToMerge );
5043   const SMDS_MeshNode* aFirstNode2ToMerge  = aMesh->FindNode( NodeID1OfSide2ToMerge );
5044   const SMDS_MeshNode* aSecondNode1ToMerge = aMesh->FindNode( NodeID2OfSide1ToMerge );
5045   const SMDS_MeshNode* aSecondNode2ToMerge = aMesh->FindNode( NodeID2OfSide2ToMerge );
5046
5047   if (!aFirstNode1ToMerge ||
5048       !aFirstNode2ToMerge )
5049     return SMESH::SMESH_MeshEditor::SEW_BAD_SIDE1_NODES;
5050   if (!aSecondNode1ToMerge||
5051       !aSecondNode2ToMerge)
5052     return SMESH::SMESH_MeshEditor::SEW_BAD_SIDE2_NODES;
5053
5054   TIDSortedElemSet aSide1Elems, aSide2Elems;
5055   arrayToSet(IDsOfSide1Elements, aMesh, aSide1Elems);
5056   arrayToSet(IDsOfSide2Elements, aMesh, aSide2Elems);
5057
5058   TPythonDump() << "error = " << this << ".SewSideElements( "
5059                 << IDsOfSide1Elements << ", "
5060                 << IDsOfSide2Elements << ", "
5061                 << NodeID1OfSide1ToMerge << ", "
5062                 << NodeID1OfSide2ToMerge << ", "
5063                 << NodeID2OfSide1ToMerge << ", "
5064                 << NodeID2OfSide2ToMerge << ")";
5065
5066   SMESH::SMESH_MeshEditor::Sew_Error error =
5067     convError( getEditor().SewSideElements (aSide1Elems, aSide2Elems,
5068                                          aFirstNode1ToMerge,
5069                                          aFirstNode2ToMerge,
5070                                          aSecondNode1ToMerge,
5071                                          aSecondNode2ToMerge));
5072
5073   declareMeshModified( /*isReComputeSafe=*/false );
5074   return error;
5075
5076   SMESH_CATCH( SMESH::throwCorbaException );
5077   return SMESH::SMESH_MeshEditor::Sew_Error(0);
5078 }
5079
5080 //================================================================================
5081 /*!
5082  * \brief Set new nodes for given element
5083  * \param ide - element id
5084  * \param newIDs - new node ids
5085  * \retval CORBA::Boolean - true if result is OK
5086  */
5087 //================================================================================
5088
5089 CORBA::Boolean SMESH_MeshEditor_i::ChangeElemNodes(CORBA::Long ide,
5090                                                    const SMESH::long_array& newIDs)
5091   throw (SALOME::SALOME_Exception)
5092 {
5093   SMESH_TRY;
5094   initData();
5095
5096   const SMDS_MeshElement* elem = getMeshDS()->FindElement(ide);
5097   if(!elem) return false;
5098
5099   int nbn = newIDs.length();
5100   int i=0;
5101   vector<const SMDS_MeshNode*> aNodes(nbn);
5102   int nbn1=-1;
5103   for(; i<nbn; i++) {
5104     const SMDS_MeshNode* aNode = getMeshDS()->FindNode(newIDs[i]);
5105     if(aNode) {
5106       nbn1++;
5107       aNodes[nbn1] = aNode;
5108     }
5109   }
5110   TPythonDump() << "isDone = " << this << ".ChangeElemNodes( "
5111                 << ide << ", " << newIDs << " )";
5112
5113   MESSAGE("ChangeElementNodes");
5114   bool res = getMeshDS()->ChangeElementNodes( elem, & aNodes[0], nbn1+1 );
5115
5116   declareMeshModified( /*isReComputeSafe=*/ !res );
5117
5118   return res;
5119
5120   SMESH_CATCH( SMESH::throwCorbaException );
5121   return 0;
5122 }
5123
5124 //=======================================================================
5125 /*!
5126  * \brief Makes a part of the mesh quadratic or bi-quadratic
5127  */
5128 //=======================================================================
5129
5130 void SMESH_MeshEditor_i::convertToQuadratic(CORBA::Boolean            theForce3d,
5131                                             CORBA::Boolean            theToBiQuad,
5132                                             SMESH::SMESH_IDSource_ptr theObject)
5133   throw (SALOME::SALOME_Exception)
5134 {
5135   SMESH_TRY;
5136   initData();
5137
5138   TIDSortedElemSet elems;
5139   bool elemsOK;
5140   if ( !( elemsOK = CORBA::is_nil( theObject )))
5141   {
5142     elemsOK =  idSourceToSet( theObject, getMeshDS(), elems,
5143                               SMDSAbs_All, /*emptyIfIsMesh=*/true );
5144   }
5145   if ( elemsOK )
5146   {
5147     if ( !elems.empty() && (*elems.begin())->GetType() == SMDSAbs_Node )
5148       THROW_SALOME_CORBA_EXCEPTION("Group of nodes is not allowed", SALOME::BAD_PARAM);
5149
5150     if ( elems.empty() ) getEditor().ConvertToQuadratic(theForce3d, theToBiQuad);
5151     else                 getEditor().ConvertToQuadratic(theForce3d, elems, theToBiQuad);
5152
5153     declareMeshModified( /*isReComputeSafe=*/false );
5154   }
5155
5156   SMESH_CATCH( SMESH::throwCorbaException );
5157 }
5158
5159 //=======================================================================
5160 //function : ConvertFromQuadratic
5161 //purpose  :
5162 //=======================================================================
5163
5164 CORBA::Boolean SMESH_MeshEditor_i::ConvertFromQuadratic()
5165   throw (SALOME::SALOME_Exception)
5166 {
5167   SMESH_TRY;
5168   initData();
5169
5170   CORBA::Boolean isDone = getEditor().ConvertFromQuadratic();
5171   TPythonDump() << this << ".ConvertFromQuadratic()";
5172   declareMeshModified( /*isReComputeSafe=*/!isDone );
5173   return isDone;
5174
5175   SMESH_CATCH( SMESH::throwCorbaException );
5176   return false;
5177 }
5178
5179 //=======================================================================
5180 //function : ConvertToQuadratic
5181 //purpose  :
5182 //=======================================================================
5183
5184 void SMESH_MeshEditor_i::ConvertToQuadratic(CORBA::Boolean theForce3d)
5185   throw (SALOME::SALOME_Exception)
5186 {
5187   convertToQuadratic( theForce3d, false );
5188   TPythonDump() << this << ".ConvertToQuadratic("<<theForce3d<<")";
5189 }
5190
5191 //================================================================================
5192 /*!
5193  * \brief Makes a part of the mesh quadratic
5194  */
5195 //================================================================================
5196
5197 void SMESH_MeshEditor_i::ConvertToQuadraticObject(CORBA::Boolean            theForce3d,
5198                                                   SMESH::SMESH_IDSource_ptr theObject)
5199   throw (SALOME::SALOME_Exception)
5200 {
5201   convertToQuadratic( theForce3d, false, theObject );
5202   TPythonDump() << this << ".ConvertToQuadraticObject("<<theForce3d<<", "<<theObject<<")";
5203 }
5204
5205 //================================================================================
5206 /*!
5207  * \brief Makes a part of the mesh bi-quadratic
5208  */
5209 //================================================================================
5210
5211 void SMESH_MeshEditor_i::ConvertToBiQuadratic(CORBA::Boolean            theForce3d,
5212                                               SMESH::SMESH_IDSource_ptr theObject)
5213   throw (SALOME::SALOME_Exception)
5214 {
5215   convertToQuadratic( theForce3d, true, theObject );
5216   TPythonDump() << this << ".ConvertToBiQuadratic("<<theForce3d<<", "<<theObject<<")";
5217 }
5218
5219 //================================================================================
5220 /*!
5221  * \brief Makes a part of the mesh linear
5222  */
5223 //================================================================================
5224
5225 void SMESH_MeshEditor_i::ConvertFromQuadraticObject(SMESH::SMESH_IDSource_ptr theObject)
5226   throw (SALOME::SALOME_Exception)
5227 {
5228   SMESH_TRY;
5229   initData();
5230
5231   TPythonDump pyDump;
5232
5233   TIDSortedElemSet elems;
5234   if ( idSourceToSet( theObject, getMeshDS(), elems, SMDSAbs_All, /*emptyIfIsMesh=*/true ))
5235   {
5236     if ( elems.empty() )
5237     {
5238       ConvertFromQuadratic();
5239     }
5240     else if ( (*elems.begin())->GetType() == SMDSAbs_Node )
5241     {
5242       THROW_SALOME_CORBA_EXCEPTION("Group of nodes is not allowed", SALOME::BAD_PARAM);
5243     }
5244     else
5245     {
5246       getEditor().ConvertFromQuadratic(elems);
5247     }
5248   }
5249   declareMeshModified( /*isReComputeSafe=*/false );
5250
5251   pyDump << this << ".ConvertFromQuadraticObject( "<<theObject<<" )";
5252
5253   SMESH_CATCH( SMESH::throwCorbaException );
5254 }
5255
5256 //=======================================================================
5257 //function : makeMesh
5258 //purpose  : create a named imported mesh
5259 //=======================================================================
5260
5261 SMESH::SMESH_Mesh_ptr SMESH_MeshEditor_i::makeMesh(const char* theMeshName)
5262 {
5263   SMESH_Gen_i*              gen = SMESH_Gen_i::GetSMESHGen();
5264   SMESH::SMESH_Mesh_var    mesh = gen->CreateEmptyMesh();
5265   SALOMEDS::Study_var     study = gen->GetCurrentStudy();
5266   SALOMEDS::SObject_wrap meshSO = gen->ObjectToSObject( study, mesh );
5267   gen->SetName( meshSO, theMeshName, "Mesh" );
5268   gen->SetPixMap( meshSO, "ICON_SMESH_TREE_MESH_IMPORTED");
5269
5270   return mesh._retn();
5271 }
5272
5273 //=======================================================================
5274 //function : dumpGroupsList
5275 //purpose  :
5276 //=======================================================================
5277
5278 void SMESH_MeshEditor_i::dumpGroupsList(TPythonDump &               theDumpPython,
5279                                         const SMESH::ListOfGroups * theGroupList)
5280 {
5281   bool isDumpGroupList = ( theGroupList && theGroupList->length() > 0 );
5282   if ( isDumpGroupList )
5283     theDumpPython << theGroupList << " = ";
5284 }
5285
5286 //================================================================================
5287 /*!
5288   \brief Generates the unique group name.
5289   \param thePrefix name prefix
5290   \return unique name
5291 */
5292 //================================================================================
5293
5294 std::string SMESH_MeshEditor_i::generateGroupName(const std::string& thePrefix)
5295 {
5296   SMESH::ListOfGroups_var groups = myMesh_i->GetGroups();
5297   set<std::string> groupNames;
5298
5299   // Get existing group names
5300   for (int i = 0, nbGroups = groups->length(); i < nbGroups; i++ ) {
5301     SMESH::SMESH_GroupBase_var aGroup = groups[i];
5302     if (CORBA::is_nil(aGroup))
5303       continue;
5304
5305     CORBA::String_var name = aGroup->GetName();
5306     groupNames.insert( name.in() );
5307   }
5308
5309   // Find new name
5310   std::string name = thePrefix;
5311   int index = 0;
5312
5313   while (!groupNames.insert(name).second)
5314     name = SMESH_Comment( thePrefix ) << "_" << index++;
5315
5316   return name;
5317 }
5318
5319 //================================================================================
5320 /*!
5321  * \brief Prepare SMESH_IDSource for work
5322  */
5323 //================================================================================
5324
5325 void SMESH_MeshEditor_i::prepareIdSource(SMESH::SMESH_IDSource_ptr theObject)
5326 {
5327   if ( SMESH::Filter_i* filter = SMESH::DownCast<SMESH::Filter_i*>( theObject ))
5328   {
5329     SMESH::SMESH_Mesh_var mesh = myMesh_i->_this();
5330     filter->SetMesh( mesh );
5331   }
5332 }
5333 //================================================================================
5334 /*!
5335  * \brief Retrieve elements of given type from SMESH_IDSource
5336  */
5337 //================================================================================
5338
5339 bool SMESH_MeshEditor_i::idSourceToSet(SMESH::SMESH_IDSource_ptr  theIDSource,
5340                                        const SMESHDS_Mesh*        theMeshDS,
5341                                        TIDSortedElemSet&          theElemSet,
5342                                        const SMDSAbs_ElementType  theType,
5343                                        const bool                 emptyIfIsMesh,
5344                                        IDSource_Error*            error)
5345
5346 {
5347   if ( error ) *error = IDSource_OK;
5348
5349   if ( CORBA::is_nil( theIDSource ))
5350   {
5351     if ( error ) *error = IDSource_INVALID;
5352     return false;
5353   }
5354   if ( emptyIfIsMesh && SMESH::DownCast<SMESH_Mesh_i*>( theIDSource ))
5355   {
5356     if ( error && getMeshDS()->GetMeshInfo().NbElements( theType ) == 0 )
5357       *error = IDSource_EMPTY;
5358     return true;
5359   }
5360   prepareIdSource( theIDSource );
5361   SMESH::long_array_var anIDs = theIDSource->GetIDs();
5362   if ( anIDs->length() == 0 )
5363   {
5364     if ( error ) *error = IDSource_EMPTY;
5365     return false;
5366   }
5367   SMESH::array_of_ElementType_var types = theIDSource->GetTypes();
5368   if ( types->length() == 1 && types[0] == SMESH::NODE ) // group of nodes
5369   {
5370     if ( theType == SMDSAbs_All || theType == SMDSAbs_Node )
5371     {
5372       arrayToSet( anIDs, getMeshDS(), theElemSet, SMDSAbs_Node );
5373     }
5374     else
5375     {
5376       if ( error ) *error = IDSource_INVALID;
5377       return false;
5378     }
5379   }
5380   else
5381   {
5382     arrayToSet( anIDs, getMeshDS(), theElemSet, theType);
5383     if ( bool(anIDs->length()) != bool(theElemSet.size()))
5384     {
5385       if ( error ) *error = IDSource_INVALID;
5386       return false;
5387     }
5388   }
5389   return true;
5390 }
5391
5392 //================================================================================
5393 /*!
5394  * \brief Duplicates given elements, i.e. creates new elements based on the
5395  *        same nodes as the given ones.
5396  * \param theElements - container of elements to duplicate.
5397  * \param theGroupName - a name of group to contain the generated elements.
5398  *                    If a group with such a name already exists, the new elements
5399  *                    are added to the existng group, else a new group is created.
5400  *                    If \a theGroupName is empty, new elements are not added 
5401  *                    in any group.
5402  * \return a group where the new elements are added. NULL if theGroupName == "".
5403  * \sa DoubleNode()
5404  */
5405 //================================================================================
5406
5407 SMESH::SMESH_Group_ptr
5408 SMESH_MeshEditor_i::DoubleElements(SMESH::SMESH_IDSource_ptr theElements,
5409                                    const char*               theGroupName)
5410   throw (SALOME::SALOME_Exception)
5411 {
5412   SMESH::SMESH_Group_var newGroup;
5413
5414   SMESH_TRY;
5415   initData();
5416
5417   TPythonDump pyDump;
5418
5419   TIDSortedElemSet elems;
5420   if ( idSourceToSet( theElements, getMeshDS(), elems, SMDSAbs_All, /*emptyIfIsMesh=*/true))
5421   {
5422     getEditor().DoubleElements( elems );
5423
5424     if ( strlen( theGroupName ) && !getEditor().GetLastCreatedElems().IsEmpty() )
5425     {
5426       // group type
5427       SMESH::ElementType type =
5428         SMESH::ElementType( getEditor().GetLastCreatedElems().Value(1)->GetType() );
5429       // find existing group
5430       SMESH::ListOfGroups_var groups = myMesh_i->GetGroups();
5431       for ( size_t i = 0; i < groups->length(); ++i )
5432         if ( groups[i]->GetType() == type )
5433         {
5434           CORBA::String_var name = groups[i]->GetName();
5435           if ( strcmp( name, theGroupName ) == 0 ) {
5436             newGroup = SMESH::SMESH_Group::_narrow( groups[i] );
5437             break;
5438           }
5439         }
5440       // create a new group
5441       if ( newGroup->_is_nil() )
5442         newGroup = myMesh_i->CreateGroup( type, theGroupName );
5443       // fill newGroup
5444       if ( SMESH_Group_i* group_i = SMESH::DownCast< SMESH_Group_i* >( newGroup ))
5445       {
5446         SMESHDS_Group* groupDS = static_cast< SMESHDS_Group* >( group_i->GetGroupDS() );
5447         const SMESH_SequenceOfElemPtr& aSeq = getEditor().GetLastCreatedElems();
5448         for ( int i = 1; i <= aSeq.Length(); i++ )
5449           groupDS->SMDSGroup().Add( aSeq(i) );
5450       }
5451     }
5452   }
5453   // python dump
5454   if ( !newGroup->_is_nil() )
5455     pyDump << newGroup << " = ";
5456   pyDump << this << ".DoubleElements( "
5457          << theElements << ", " << "'" << theGroupName <<"')";
5458
5459   SMESH_CATCH( SMESH::throwCorbaException );
5460
5461   return newGroup._retn();
5462 }
5463
5464 //================================================================================
5465 /*!
5466   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5467   \param theNodes - identifiers of nodes to be doubled
5468   \param theModifiedElems - identifiers of elements to be updated by the new (doubled)
5469          nodes. If list of element identifiers is empty then nodes are doubled but
5470          they not assigned to elements
5471   \return TRUE if operation has been completed successfully, FALSE otherwise
5472   \sa DoubleNode(), DoubleNodeGroup(), DoubleNodeGroups()
5473 */
5474 //================================================================================
5475
5476 CORBA::Boolean SMESH_MeshEditor_i::DoubleNodes( const SMESH::long_array& theNodes,
5477                                                 const SMESH::long_array& theModifiedElems )
5478   throw (SALOME::SALOME_Exception)
5479 {
5480   SMESH_TRY;
5481   initData();
5482
5483   list< int > aListOfNodes;
5484   int i, n;
5485   for ( i = 0, n = theNodes.length(); i < n; i++ )
5486     aListOfNodes.push_back( theNodes[ i ] );
5487
5488   list< int > aListOfElems;
5489   for ( i = 0, n = theModifiedElems.length(); i < n; i++ )
5490     aListOfElems.push_back( theModifiedElems[ i ] );
5491
5492   bool aResult = getEditor().DoubleNodes( aListOfNodes, aListOfElems );
5493
5494   declareMeshModified( /*isReComputeSafe=*/ !aResult );
5495
5496   // Update Python script
5497   TPythonDump() << this << ".DoubleNodes( " << theNodes << ", "<< theModifiedElems << " )";
5498
5499   return aResult;
5500
5501   SMESH_CATCH( SMESH::throwCorbaException );
5502   return 0;
5503 }
5504
5505 //================================================================================
5506 /*!
5507   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5508   This method provided for convenience works as DoubleNodes() described above.
5509   \param theNodeId - identifier of node to be doubled.
5510   \param theModifiedElems - identifiers of elements to be updated.
5511   \return TRUE if operation has been completed successfully, FALSE otherwise
5512   \sa DoubleNodes(), DoubleNodeGroup(), DoubleNodeGroups()
5513 */
5514 //================================================================================
5515
5516 CORBA::Boolean SMESH_MeshEditor_i::DoubleNode( CORBA::Long              theNodeId,
5517                                                const SMESH::long_array& theModifiedElems )
5518   throw (SALOME::SALOME_Exception)
5519 {
5520   SMESH_TRY;
5521   SMESH::long_array_var aNodes = new SMESH::long_array;
5522   aNodes->length( 1 );
5523   aNodes[ 0 ] = theNodeId;
5524
5525   TPythonDump pyDump; // suppress dump by the next line
5526
5527   CORBA::Boolean done = DoubleNodes( aNodes, theModifiedElems );
5528
5529   pyDump << this << ".DoubleNode( " << theNodeId << ", " << theModifiedElems << " )";
5530
5531   return done;
5532
5533   SMESH_CATCH( SMESH::throwCorbaException );
5534   return 0;
5535 }
5536
5537 //================================================================================
5538 /*!
5539   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5540   This method provided for convenience works as DoubleNodes() described above.
5541   \param theNodes - group of nodes to be doubled.
5542   \param theModifiedElems - group of elements to be updated.
5543   \return TRUE if operation has been completed successfully, FALSE otherwise
5544   \sa DoubleNode(), DoubleNodes(), DoubleNodeGroups()
5545 */
5546 //================================================================================
5547
5548 CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeGroup(SMESH::SMESH_GroupBase_ptr theNodes,
5549                                                    SMESH::SMESH_GroupBase_ptr theModifiedElems )
5550   throw (SALOME::SALOME_Exception)
5551 {
5552   SMESH_TRY;
5553   if ( CORBA::is_nil( theNodes ) && theNodes->GetType() != SMESH::NODE )
5554     return false;
5555
5556   SMESH::long_array_var aNodes = theNodes->GetListOfID();
5557   SMESH::long_array_var aModifiedElems;
5558   if ( !CORBA::is_nil( theModifiedElems ) )
5559     aModifiedElems = theModifiedElems->GetListOfID();
5560   else
5561   {
5562     aModifiedElems = new SMESH::long_array;
5563     aModifiedElems->length( 0 );
5564   }
5565
5566   TPythonDump pyDump; // suppress dump by the next line
5567
5568   bool done = DoubleNodes( aNodes, aModifiedElems );
5569
5570   pyDump << this << ".DoubleNodeGroup( " << theNodes << ", " << theModifiedElems << " )";
5571
5572   return done;
5573
5574   SMESH_CATCH( SMESH::throwCorbaException );
5575   return 0;
5576 }
5577
5578 //================================================================================
5579 /*!
5580  * \brief Creates a hole in a mesh by doubling the nodes of some particular elements.
5581  * Works as DoubleNodeGroup(), but returns a new group with newly created nodes.
5582  * \param theNodes - group of nodes to be doubled.
5583  * \param theModifiedElems - group of elements to be updated.
5584  * \return a new group with newly created nodes
5585  * \sa DoubleNodeGroup()
5586  */
5587 //================================================================================
5588
5589 SMESH::SMESH_Group_ptr
5590 SMESH_MeshEditor_i::DoubleNodeGroupNew( SMESH::SMESH_GroupBase_ptr theNodes,
5591                                         SMESH::SMESH_GroupBase_ptr theModifiedElems )
5592   throw (SALOME::SALOME_Exception)
5593 {
5594   SMESH_TRY;
5595   SMESH::SMESH_Group_var aNewGroup;
5596
5597   if ( CORBA::is_nil( theNodes ) && theNodes->GetType() != SMESH::NODE )
5598     return aNewGroup._retn();
5599
5600   // Duplicate nodes
5601   SMESH::long_array_var aNodes = theNodes->GetListOfID();
5602   SMESH::long_array_var aModifiedElems;
5603   if ( !CORBA::is_nil( theModifiedElems ) )
5604     aModifiedElems = theModifiedElems->GetListOfID();
5605   else {
5606     aModifiedElems = new SMESH::long_array;
5607     aModifiedElems->length( 0 );
5608   }
5609
5610   TPythonDump pyDump; // suppress dump by the next line
5611
5612   bool aResult = DoubleNodes( aNodes, aModifiedElems );
5613   if ( aResult )
5614   {
5615     // Create group with newly created nodes
5616     SMESH::long_array_var anIds = GetLastCreatedNodes();
5617     if (anIds->length() > 0) {
5618       std::string anUnindexedName (theNodes->GetName());
5619       std::string aNewName = generateGroupName(anUnindexedName + "_double");
5620       aNewGroup = myMesh_i->CreateGroup(SMESH::NODE, aNewName.c_str());
5621       aNewGroup->Add(anIds);
5622       pyDump << aNewGroup << " = ";
5623     }
5624   }
5625
5626   pyDump << this << ".DoubleNodeGroupNew( " << theNodes << ", "
5627          << theModifiedElems << " )";
5628
5629   return aNewGroup._retn();
5630
5631   SMESH_CATCH( SMESH::throwCorbaException );
5632   return 0;
5633 }
5634
5635 //================================================================================
5636 /*!
5637   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5638   This method provided for convenience works as DoubleNodes() described above.
5639   \param theNodes - list of groups of nodes to be doubled
5640   \param theModifiedElems - list of groups of elements to be updated.
5641   \return TRUE if operation has been completed successfully, FALSE otherwise
5642   \sa DoubleNode(), DoubleNodeGroup(), DoubleNodes()
5643 */
5644 //================================================================================
5645
5646 CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeGroups(const SMESH::ListOfGroups& theNodes,
5647                                                     const SMESH::ListOfGroups& theModifiedElems )
5648   throw (SALOME::SALOME_Exception)
5649 {
5650   SMESH_TRY;
5651   initData();
5652
5653   std::list< int > aNodes;
5654   int i, n, j, m;
5655   for ( i = 0, n = theNodes.length(); i < n; i++ )
5656   {
5657     SMESH::SMESH_GroupBase_var aGrp = theNodes[ i ];
5658     if ( !CORBA::is_nil( aGrp ) && aGrp->GetType() == SMESH::NODE )
5659     {
5660       SMESH::long_array_var aCurr = aGrp->GetListOfID();
5661       for ( j = 0, m = aCurr->length(); j < m; j++ )
5662         aNodes.push_back( aCurr[ j ] );
5663     }
5664   }
5665
5666   std::list< int > anElems;
5667   for ( i = 0, n = theModifiedElems.length(); i < n; i++ )
5668   {
5669     SMESH::SMESH_GroupBase_var aGrp = theModifiedElems[ i ];
5670     if ( !CORBA::is_nil( aGrp ) && aGrp->GetType() != SMESH::NODE )
5671     {
5672       SMESH::long_array_var aCurr = aGrp->GetListOfID();
5673       for ( j = 0, m = aCurr->length(); j < m; j++ )
5674         anElems.push_back( aCurr[ j ] );
5675     }
5676   }
5677
5678   bool aResult = getEditor().DoubleNodes( aNodes, anElems );
5679
5680   declareMeshModified( /*isReComputeSafe=*/false );
5681
5682   TPythonDump() << this << ".DoubleNodeGroups( " << theNodes << ", " << theModifiedElems << " )";
5683
5684   return aResult;
5685
5686   SMESH_CATCH( SMESH::throwCorbaException );
5687   return 0;
5688 }
5689
5690 //================================================================================
5691 /*!
5692  * \brief Creates a hole in a mesh by doubling the nodes of some particular elements.
5693  * Works as DoubleNodeGroups(), but returns a new group with newly created nodes.
5694  * \param theNodes - group of nodes to be doubled.
5695  * \param theModifiedElems - group of elements to be updated.
5696  * \return a new group with newly created nodes
5697  * \sa DoubleNodeGroups()
5698  */
5699 //================================================================================
5700
5701 SMESH::SMESH_Group_ptr
5702 SMESH_MeshEditor_i::DoubleNodeGroupsNew( const SMESH::ListOfGroups& theNodes,
5703                                          const SMESH::ListOfGroups& theModifiedElems )
5704   throw (SALOME::SALOME_Exception)
5705 {
5706   SMESH::SMESH_Group_var aNewGroup;
5707
5708   TPythonDump pyDump; // suppress dump by the next line
5709
5710   bool aResult = DoubleNodeGroups( theNodes, theModifiedElems );
5711
5712   if ( aResult )
5713   {
5714     // Create group with newly created nodes
5715     SMESH::long_array_var anIds = GetLastCreatedNodes();
5716     if (anIds->length() > 0) {
5717       std::string anUnindexedName (theNodes[0]->GetName());
5718       std::string aNewName = generateGroupName(anUnindexedName + "_double");
5719       aNewGroup = myMesh_i->CreateGroup(SMESH::NODE, aNewName.c_str());
5720       aNewGroup->Add(anIds);
5721       pyDump << aNewGroup << " = ";
5722     }
5723   }
5724
5725   pyDump << this << ".DoubleNodeGroupsNew( " << theNodes << ", "
5726          << theModifiedElems << " )";
5727
5728   return aNewGroup._retn();
5729 }
5730
5731
5732 //================================================================================
5733 /*!
5734   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5735   \param theElems - the list of elements (edges or faces) to be replicated
5736   The nodes for duplication could be found from these elements
5737   \param theNodesNot - list of nodes to NOT replicate
5738   \param theAffectedElems - the list of elements (cells and edges) to which the
5739   replicated nodes should be associated to.
5740   \return TRUE if operation has been completed successfully, FALSE otherwise
5741   \sa DoubleNodeGroup(), DoubleNodeGroups()
5742 */
5743 //================================================================================
5744
5745 CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeElem( const SMESH::long_array& theElems,
5746                                                    const SMESH::long_array& theNodesNot,
5747                                                    const SMESH::long_array& theAffectedElems )
5748   throw (SALOME::SALOME_Exception)
5749 {
5750   SMESH_TRY;
5751   initData();
5752
5753   SMESHDS_Mesh* aMeshDS = getMeshDS();
5754   TIDSortedElemSet anElems, aNodes, anAffected;
5755   arrayToSet(theElems, aMeshDS, anElems, SMDSAbs_All);
5756   arrayToSet(theNodesNot, aMeshDS, aNodes, SMDSAbs_Node);
5757   arrayToSet(theAffectedElems, aMeshDS, anAffected, SMDSAbs_All);
5758
5759   bool aResult = getEditor().DoubleNodes( anElems, aNodes, anAffected );
5760
5761   // Update Python script
5762   TPythonDump() << this << ".DoubleNodeElem( " << theElems << ", "
5763                 << theNodesNot << ", " << theAffectedElems << " )";
5764
5765   declareMeshModified( /*isReComputeSafe=*/false );
5766   return aResult;
5767
5768   SMESH_CATCH( SMESH::throwCorbaException );
5769   return 0;
5770 }
5771
5772 //================================================================================
5773 /*!
5774   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5775   \param theElems - the list of elements (edges or faces) to be replicated
5776   The nodes for duplication could be found from these elements
5777   \param theNodesNot - list of nodes to NOT replicate
5778   \param theShape - shape to detect affected elements (element which geometric center
5779   located on or inside shape).
5780   The replicated nodes should be associated to affected elements.
5781   \return TRUE if operation has been completed successfully, FALSE otherwise
5782   \sa DoubleNodeGroupInRegion(), DoubleNodeGroupsInRegion()
5783 */
5784 //================================================================================
5785
5786 CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeElemInRegion ( const SMESH::long_array& theElems,
5787                                                             const SMESH::long_array& theNodesNot,
5788                                                             GEOM::GEOM_Object_ptr    theShape )
5789   throw (SALOME::SALOME_Exception)
5790 {
5791   SMESH_TRY;
5792   initData();
5793
5794
5795   SMESHDS_Mesh* aMeshDS = getMeshDS();
5796   TIDSortedElemSet anElems, aNodes;
5797   arrayToSet(theElems, aMeshDS, anElems, SMDSAbs_All);
5798   arrayToSet(theNodesNot, aMeshDS, aNodes, SMDSAbs_Node);
5799
5800   TopoDS_Shape aShape = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape( theShape );
5801   bool aResult = getEditor().DoubleNodesInRegion( anElems, aNodes, aShape );
5802
5803   // Update Python script
5804   TPythonDump() << "isDone = " << this << ".DoubleNodeElemInRegion( " << theElems << ", "
5805                 << theNodesNot << ", " << theShape << " )";
5806
5807   declareMeshModified( /*isReComputeSafe=*/false );
5808   return aResult;
5809
5810   SMESH_CATCH( SMESH::throwCorbaException );
5811   return 0;
5812 }
5813
5814 //================================================================================
5815 /*!
5816   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5817   \param theElems - group of of elements (edges or faces) to be replicated
5818   \param theNodesNot - group of nodes not to replicated
5819   \param theAffectedElems - group of elements to which the replicated nodes
5820   should be associated to.
5821   \return TRUE if operation has been completed successfully, FALSE otherwise
5822   \sa DoubleNodes(), DoubleNodeGroups()
5823 */
5824 //================================================================================
5825
5826 CORBA::Boolean
5827 SMESH_MeshEditor_i::DoubleNodeElemGroup(SMESH::SMESH_GroupBase_ptr theElems,
5828                                         SMESH::SMESH_GroupBase_ptr theNodesNot,
5829                                         SMESH::SMESH_GroupBase_ptr theAffectedElems)
5830   throw (SALOME::SALOME_Exception)
5831 {
5832   SMESH_TRY;
5833   if ( CORBA::is_nil( theElems ) && theElems->GetType() == SMESH::NODE )
5834     return false;
5835
5836   initData();
5837
5838
5839   SMESHDS_Mesh* aMeshDS = getMeshDS();
5840   TIDSortedElemSet anElems, aNodes, anAffected;
5841   idSourceToSet( theElems, aMeshDS, anElems, SMDSAbs_All );
5842   idSourceToSet( theNodesNot, aMeshDS, aNodes, SMDSAbs_Node );
5843   idSourceToSet( theAffectedElems, aMeshDS, anAffected, SMDSAbs_All );
5844
5845   bool aResult = getEditor().DoubleNodes( anElems, aNodes, anAffected );
5846
5847   // Update Python script
5848   TPythonDump() << "isDone = " << this << ".DoubleNodeElemGroup( " << theElems << ", "
5849                 << theNodesNot << ", " << theAffectedElems << " )";
5850
5851   declareMeshModified( /*isReComputeSafe=*/false );
5852   return aResult;
5853
5854   SMESH_CATCH( SMESH::throwCorbaException );
5855   return 0;
5856 }
5857
5858 //================================================================================
5859 /*!
5860  * \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5861  * Works as DoubleNodeElemGroup(), but returns a new group with newly created elements.
5862  * \param theElems - group of of elements (edges or faces) to be replicated
5863  * \param theNodesNot - group of nodes not to replicated
5864  * \param theAffectedElems - group of elements to which the replicated nodes
5865  *        should be associated to.
5866  * \return a new group with newly created elements
5867  * \sa DoubleNodeElemGroup()
5868  */
5869 //================================================================================
5870
5871 SMESH::SMESH_Group_ptr
5872 SMESH_MeshEditor_i::DoubleNodeElemGroupNew(SMESH::SMESH_GroupBase_ptr theElems,
5873                                            SMESH::SMESH_GroupBase_ptr theNodesNot,
5874                                            SMESH::SMESH_GroupBase_ptr theAffectedElems)
5875   throw (SALOME::SALOME_Exception)
5876 {
5877   TPythonDump pyDump;
5878   SMESH::ListOfGroups_var twoGroups = DoubleNodeElemGroup2New( theElems,
5879                                                                theNodesNot,
5880                                                                theAffectedElems,
5881                                                                true, false );
5882   SMESH::SMESH_GroupBase_var baseGroup = twoGroups[0].in();
5883   SMESH::SMESH_Group_var     elemGroup = SMESH::SMESH_Group::_narrow( baseGroup );
5884
5885   pyDump << elemGroup << " = " << this << ".DoubleNodeElemGroupNew( "
5886          << theElems         << ", "
5887          << theNodesNot      << ", "
5888          << theAffectedElems << " )";
5889
5890   return elemGroup._retn();
5891 }
5892
5893 //================================================================================
5894 /*!
5895  * \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5896  * Works as DoubleNodeElemGroup(), but returns a new group with newly created elements.
5897  * \param theElems - group of of elements (edges or faces) to be replicated
5898  * \param theNodesNot - group of nodes not to replicated
5899  * \param theAffectedElems - group of elements to which the replicated nodes
5900  *        should be associated to.
5901  * \return a new group with newly created elements
5902  * \sa DoubleNodeElemGroup()
5903  */
5904 //================================================================================
5905
5906 SMESH::ListOfGroups*
5907 SMESH_MeshEditor_i::DoubleNodeElemGroup2New(SMESH::SMESH_GroupBase_ptr theElems,
5908                                             SMESH::SMESH_GroupBase_ptr theNodesNot,
5909                                             SMESH::SMESH_GroupBase_ptr theAffectedElems,
5910                                             CORBA::Boolean             theElemGroupNeeded,
5911                                             CORBA::Boolean             theNodeGroupNeeded)
5912   throw (SALOME::SALOME_Exception)
5913 {
5914   SMESH_TRY;
5915   SMESH::SMESH_Group_var aNewElemGroup, aNewNodeGroup;
5916   SMESH::ListOfGroups_var aTwoGroups = new SMESH::ListOfGroups();
5917   aTwoGroups->length( 2 );
5918
5919   if ( CORBA::is_nil( theElems ) && theElems->GetType() == SMESH::NODE )
5920     return aTwoGroups._retn();
5921
5922   initData();
5923
5924
5925   SMESHDS_Mesh* aMeshDS = getMeshDS();
5926   TIDSortedElemSet anElems, aNodes, anAffected;
5927   idSourceToSet( theElems, aMeshDS, anElems, SMDSAbs_All );
5928   idSourceToSet( theNodesNot, aMeshDS, aNodes, SMDSAbs_Node );
5929   idSourceToSet( theAffectedElems, aMeshDS, anAffected, SMDSAbs_All );
5930
5931
5932   bool aResult = getEditor().DoubleNodes( anElems, aNodes, anAffected );
5933
5934   declareMeshModified( /*isReComputeSafe=*/ !aResult );
5935
5936   TPythonDump pyDump;
5937
5938   if ( aResult )
5939   {
5940     // Create group with newly created elements
5941     CORBA::String_var elemGroupName = theElems->GetName();
5942     std::string aNewName = generateGroupName( std::string(elemGroupName.in()) + "_double");
5943     if ( !getEditor().GetLastCreatedElems().IsEmpty() && theElemGroupNeeded )
5944     {
5945       SMESH::long_array_var anIds = GetLastCreatedElems();
5946       SMESH::ElementType aGroupType = myMesh_i->GetElementType(anIds[0], true);
5947       aNewElemGroup = myMesh_i->CreateGroup(aGroupType, aNewName.c_str());
5948       aNewElemGroup->Add(anIds);
5949     }
5950     if ( !getEditor().GetLastCreatedNodes().IsEmpty() && theNodeGroupNeeded )
5951     {
5952       SMESH::long_array_var anIds = GetLastCreatedNodes();
5953       aNewNodeGroup = myMesh_i->CreateGroup(SMESH::NODE, aNewName.c_str());
5954       aNewNodeGroup->Add(anIds);
5955     }
5956   }
5957
5958   // Update Python script
5959
5960   pyDump << "[ ";
5961   if ( aNewElemGroup->_is_nil() ) pyDump << "nothing, ";
5962   else                            pyDump << aNewElemGroup << ", ";
5963   if ( aNewNodeGroup->_is_nil() ) pyDump << "nothing ] = ";
5964   else                            pyDump << aNewNodeGroup << " ] = ";
5965
5966   pyDump << this << ".DoubleNodeElemGroup2New( " << theElems << ", "
5967          << theNodesNot        << ", "
5968          << theAffectedElems   << ", "
5969          << theElemGroupNeeded << ", "
5970          << theNodeGroupNeeded <<" )";
5971
5972   aTwoGroups[0] = aNewElemGroup._retn();
5973   aTwoGroups[1] = aNewNodeGroup._retn();
5974   return aTwoGroups._retn();
5975
5976   SMESH_CATCH( SMESH::throwCorbaException );
5977   return 0;
5978 }
5979
5980 //================================================================================
5981 /*!
5982   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5983   \param theElems - group of of elements (edges or faces) to be replicated
5984   \param theNodesNot - group of nodes not to replicated
5985   \param theShape - shape to detect affected elements (element which geometric center
5986   located on or inside shape).
5987   The replicated nodes should be associated to affected elements.
5988   \return TRUE if operation has been completed successfully, FALSE otherwise
5989   \sa DoubleNodesInRegion(), DoubleNodeGroupsInRegion()
5990 */
5991 //================================================================================
5992
5993 CORBA::Boolean
5994 SMESH_MeshEditor_i::DoubleNodeElemGroupInRegion(SMESH::SMESH_GroupBase_ptr theElems,
5995                                                 SMESH::SMESH_GroupBase_ptr theNodesNot,
5996                                                 GEOM::GEOM_Object_ptr      theShape )
5997   throw (SALOME::SALOME_Exception)
5998 {
5999   SMESH_TRY;
6000   if ( CORBA::is_nil( theElems ) && theElems->GetType() == SMESH::NODE )
6001     return false;
6002
6003   initData();
6004
6005
6006   SMESHDS_Mesh* aMeshDS = getMeshDS();
6007   TIDSortedElemSet anElems, aNodes, anAffected;
6008   idSourceToSet( theElems, aMeshDS, anElems, SMDSAbs_All );
6009   idSourceToSet( theNodesNot, aMeshDS, aNodes, SMDSAbs_Node );
6010
6011   TopoDS_Shape aShape = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape( theShape );
6012   bool aResult = getEditor().DoubleNodesInRegion( anElems, aNodes, aShape );
6013
6014
6015   declareMeshModified( /*isReComputeSafe=*/ !aResult );
6016
6017   // Update Python script
6018   TPythonDump() << "isDone = " << this << ".DoubleNodeElemGroupInRegion( " << theElems << ", "
6019                 << theNodesNot << ", " << theShape << " )";
6020   return aResult;
6021
6022   SMESH_CATCH( SMESH::throwCorbaException );
6023   return 0;
6024 }
6025
6026 //================================================================================
6027 /*!
6028  * \brief Re-load elements from a list of groups into a TIDSortedElemSet
6029  *  \param [in] theGrpList - groups
6030  *  \param [in] theMeshDS -  mesh
6031  *  \param [out] theElemSet - set of elements
6032  *  \param [in] theIsNodeGrp - is \a theGrpList includes goups of nodes
6033  */
6034 //================================================================================
6035
6036 static void listOfGroupToSet(const SMESH::ListOfGroups& theGrpList,
6037                              SMESHDS_Mesh*              theMeshDS,
6038                              TIDSortedElemSet&          theElemSet,
6039                              const bool                 theIsNodeGrp)
6040 {
6041   for ( int i = 0, n = theGrpList.length(); i < n; i++ )
6042   {
6043     SMESH::SMESH_GroupBase_var aGrp = theGrpList[ i ];
6044     if ( !CORBA::is_nil( aGrp ) && (theIsNodeGrp ? aGrp->GetType() == SMESH::NODE
6045                                     : aGrp->GetType() != SMESH::NODE ) )
6046     {
6047       SMESH::long_array_var anIDs = aGrp->GetIDs();
6048       arrayToSet( anIDs, theMeshDS, theElemSet, theIsNodeGrp ? SMDSAbs_Node : SMDSAbs_All );
6049     }
6050   }
6051 }
6052
6053 //================================================================================
6054 /*!
6055   \brief Creates a hole in a mesh by doubling the nodes of some particular elements.
6056   This method provided for convenience works as DoubleNodes() described above.
6057   \param theElems - list of groups of elements (edges or faces) to be replicated
6058   \param theNodesNot - list of groups of nodes not to replicated
6059   \param theAffectedElems - group of elements to which the replicated nodes
6060   should be associated to.
6061   \return TRUE if operation has been completed successfully, FALSE otherwise
6062   \sa DoubleNodeGroup(), DoubleNodes(), DoubleNodeElemGroupsNew()
6063 */
6064 //================================================================================
6065
6066 CORBA::Boolean
6067 SMESH_MeshEditor_i::DoubleNodeElemGroups(const SMESH::ListOfGroups& theElems,
6068                                          const SMESH::ListOfGroups& theNodesNot,
6069                                          const SMESH::ListOfGroups& theAffectedElems)
6070   throw (SALOME::SALOME_Exception)
6071 {
6072   SMESH_TRY;
6073   initData();
6074
6075
6076   SMESHDS_Mesh* aMeshDS = getMeshDS();
6077   TIDSortedElemSet anElems, aNodes, anAffected;
6078   listOfGroupToSet(theElems, aMeshDS, anElems, false );
6079   listOfGroupToSet(theNodesNot, aMeshDS, aNodes, true );
6080   listOfGroupToSet(theAffectedElems, aMeshDS, anAffected, false );
6081
6082   bool aResult = getEditor().DoubleNodes( anElems, aNodes, anAffected );
6083
6084   // Update Python script
6085   TPythonDump() << "isDone = " << this << ".DoubleNodeElemGroups( " << &theElems << ", "
6086                 << &theNodesNot << ", " << &theAffectedElems << " )";
6087
6088   declareMeshModified( /*isReComputeSafe=*/false );
6089   return aResult;
6090
6091   SMESH_CATCH( SMESH::throwCorbaException );
6092   return 0;
6093 }
6094
6095 //================================================================================
6096 /*!
6097  * \brief Creates a hole in a mesh by doubling the nodes of some particular elements
6098  * Works as DoubleNodeElemGroups(), but returns a new group with newly created elements.
6099   \param theElems - list of groups of elements (edges or faces) to be replicated
6100   \param theNodesNot - list of groups of nodes not to replicated
6101   \param theAffectedElems - group of elements to which the replicated nodes
6102   should be associated to.
6103  * \return a new group with newly created elements
6104  * \sa DoubleNodeElemGroups()
6105  */
6106 //================================================================================
6107
6108 SMESH::SMESH_Group_ptr
6109 SMESH_MeshEditor_i::DoubleNodeElemGroupsNew(const SMESH::ListOfGroups& theElems,
6110                                             const SMESH::ListOfGroups& theNodesNot,
6111                                             const SMESH::ListOfGroups& theAffectedElems)
6112   throw (SALOME::SALOME_Exception)
6113 {
6114   TPythonDump pyDump;
6115   SMESH::ListOfGroups_var twoGroups = DoubleNodeElemGroups2New( theElems,
6116                                                                 theNodesNot,
6117                                                                 theAffectedElems,
6118                                                                 true, false );
6119   SMESH::SMESH_GroupBase_var baseGroup = twoGroups[0].in();
6120   SMESH::SMESH_Group_var     elemGroup = SMESH::SMESH_Group::_narrow( baseGroup );
6121
6122   pyDump << elemGroup << " = " << this << ".DoubleNodeElemGroupsNew( "
6123          << theElems         << ", "
6124          << theNodesNot      << ", "
6125          << theAffectedElems << " )";
6126
6127   return elemGroup._retn();
6128 }
6129
6130 //================================================================================
6131 /*!
6132  * \brief Creates a hole in a mesh by doubling the nodes of some particular elements
6133  * Works as DoubleNodeElemGroups(), but returns a new group with newly created elements.
6134   \param theElems - list of groups of elements (edges or faces) to be replicated
6135   \param theNodesNot - list of groups of nodes not to replicated
6136   \param theAffectedElems - group of elements to which the replicated nodes
6137   should be associated to.
6138  * \return a new group with newly created elements
6139  * \sa DoubleNodeElemGroups()
6140  */
6141 //================================================================================
6142
6143 SMESH::ListOfGroups*
6144 SMESH_MeshEditor_i::DoubleNodeElemGroups2New(const SMESH::ListOfGroups& theElems,
6145                                              const SMESH::ListOfGroups& theNodesNot,
6146                                              const SMESH::ListOfGroups& theAffectedElems,
6147                                              CORBA::Boolean             theElemGroupNeeded,
6148                                              CORBA::Boolean             theNodeGroupNeeded)
6149   throw (SALOME::SALOME_Exception)
6150 {
6151   SMESH_TRY;
6152   SMESH::SMESH_Group_var aNewElemGroup, aNewNodeGroup;
6153   SMESH::ListOfGroups_var aTwoGroups = new SMESH::ListOfGroups();
6154   aTwoGroups->length( 2 );
6155   
6156   initData();
6157
6158
6159   SMESHDS_Mesh* aMeshDS = getMeshDS();
6160   TIDSortedElemSet anElems, aNodes, anAffected;
6161   listOfGroupToSet(theElems, aMeshDS, anElems, false );
6162   listOfGroupToSet(theNodesNot, aMeshDS, aNodes, true );
6163   listOfGroupToSet(theAffectedElems, aMeshDS, anAffected, false );
6164
6165   bool aResult = getEditor().DoubleNodes( anElems, aNodes, anAffected );
6166
6167   declareMeshModified( /*isReComputeSafe=*/ !aResult );
6168
6169   TPythonDump pyDump;
6170   if ( aResult )
6171   {
6172     // Create group with newly created elements
6173     CORBA::String_var elemGroupName = theElems[0]->GetName();
6174     std::string aNewName = generateGroupName( std::string(elemGroupName.in()) + "_double");
6175     if ( !getEditor().GetLastCreatedElems().IsEmpty() && theElemGroupNeeded )
6176     {
6177       SMESH::long_array_var anIds = GetLastCreatedElems();
6178       SMESH::ElementType aGroupType = myMesh_i->GetElementType(anIds[0], true);
6179       aNewElemGroup = myMesh_i->CreateGroup(aGroupType, aNewName.c_str());
6180       aNewElemGroup->Add(anIds);
6181     }
6182     if ( !getEditor().GetLastCreatedNodes().IsEmpty() && theNodeGroupNeeded )
6183     {
6184       SMESH::long_array_var anIds = GetLastCreatedNodes();
6185       aNewNodeGroup = myMesh_i->CreateGroup(SMESH::NODE, aNewName.c_str());
6186       aNewNodeGroup->Add(anIds);
6187     }
6188   }
6189
6190   // Update Python script
6191
6192   pyDump << "[ ";
6193   if ( aNewElemGroup->_is_nil() ) pyDump << "nothing, ";
6194   else                            pyDump << aNewElemGroup << ", ";
6195   if ( aNewNodeGroup->_is_nil() ) pyDump << "nothing ] = ";
6196   else                            pyDump << aNewNodeGroup << " ] = ";
6197
6198   pyDump << this << ".DoubleNodeElemGroups2New( " << &theElems << ", "
6199          << &theNodesNot       << ", "
6200          << &theAffectedElems  << ", "
6201          << theElemGroupNeeded << ", "
6202          << theNodeGroupNeeded << " )";
6203
6204   aTwoGroups[0] = aNewElemGroup._retn();
6205   aTwoGroups[1] = aNewNodeGroup._retn();
6206   return aTwoGroups._retn();
6207
6208   SMESH_CATCH( SMESH::throwCorbaException );
6209   return 0;
6210 }
6211
6212 //================================================================================
6213 /*!
6214   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
6215   This method provided for convenience works as DoubleNodes() described above.
6216   \param theElems - list of groups of elements (edges or faces) to be replicated
6217   \param theNodesNot - list of groups of nodes not to replicated
6218   \param theShape - shape to detect affected elements (element which geometric center
6219   located on or inside shape).
6220   The replicated nodes should be associated to affected elements.
6221   \return TRUE if operation has been completed successfully, FALSE otherwise
6222   \sa DoubleNodeGroupInRegion(), DoubleNodesInRegion()
6223 */
6224 //================================================================================
6225
6226 CORBA::Boolean
6227 SMESH_MeshEditor_i::DoubleNodeElemGroupsInRegion(const SMESH::ListOfGroups& theElems,
6228                                                  const SMESH::ListOfGroups& theNodesNot,
6229                                                  GEOM::GEOM_Object_ptr      theShape )
6230   throw (SALOME::SALOME_Exception)
6231 {
6232   SMESH_TRY;
6233   initData();
6234
6235
6236   SMESHDS_Mesh* aMeshDS = getMeshDS();
6237   TIDSortedElemSet anElems, aNodes;
6238   listOfGroupToSet(theElems, aMeshDS, anElems,false );
6239   listOfGroupToSet(theNodesNot, aMeshDS, aNodes, true );
6240
6241   TopoDS_Shape aShape = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape( theShape );
6242   bool aResult = getEditor().DoubleNodesInRegion( anElems, aNodes, aShape );
6243
6244   // Update Python script
6245   TPythonDump() << "isDone = " << this << ".DoubleNodeElemGroupsInRegion( " << &theElems << ", "
6246                 << &theNodesNot << ", " << theShape << " )";
6247
6248   declareMeshModified( /*isReComputeSafe=*/ !aResult );
6249   return aResult;
6250
6251   SMESH_CATCH( SMESH::throwCorbaException );
6252   return 0;
6253 }
6254
6255 //================================================================================
6256 /*!
6257   \brief Identify the elements that will be affected by node duplication (actual
6258          duplication is not performed.
6259   This method is the first step of DoubleNodeElemGroupsInRegion.
6260   \param theElems - list of groups of elements (edges or faces) to be replicated
6261   \param theNodesNot - list of groups of nodes not to replicated
6262   \param theShape - shape to detect affected elements (element which geometric center
6263          located on or inside shape).
6264          The replicated nodes should be associated to affected elements.
6265   \return groups of affected elements
6266   \sa DoubleNodeElemGroupsInRegion()
6267 */
6268 //================================================================================
6269 SMESH::ListOfGroups*
6270 SMESH_MeshEditor_i::AffectedElemGroupsInRegion( const SMESH::ListOfGroups& theElems,
6271                                                 const SMESH::ListOfGroups& theNodesNot,
6272                                                 GEOM::GEOM_Object_ptr      theShape )
6273   throw (SALOME::SALOME_Exception)
6274 {
6275   SMESH_TRY;
6276   MESSAGE("AffectedElemGroupsInRegion");
6277   SMESH::ListOfGroups_var aListOfGroups = new SMESH::ListOfGroups();
6278   bool isEdgeGroup = false;
6279   bool isFaceGroup = false;
6280   bool isVolumeGroup = false;
6281   SMESH::SMESH_Group_var aNewEdgeGroup = myMesh_i->CreateGroup(SMESH::EDGE, "affectedEdges");
6282   SMESH::SMESH_Group_var aNewFaceGroup = myMesh_i->CreateGroup(SMESH::FACE, "affectedFaces");
6283   SMESH::SMESH_Group_var aNewVolumeGroup = myMesh_i->CreateGroup(SMESH::VOLUME, "affectedVolumes");
6284
6285   initData();
6286
6287   ::SMESH_MeshEditor aMeshEditor(myMesh);
6288
6289   SMESHDS_Mesh* aMeshDS = getMeshDS();
6290   TIDSortedElemSet anElems, aNodes;
6291   listOfGroupToSet(theElems, aMeshDS, anElems, false);
6292   listOfGroupToSet(theNodesNot, aMeshDS, aNodes, true);
6293
6294   TopoDS_Shape aShape = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape(theShape);
6295   TIDSortedElemSet anAffected;
6296   bool aResult = aMeshEditor.AffectedElemGroupsInRegion(anElems, aNodes, aShape, anAffected);
6297
6298
6299   declareMeshModified( /*isReComputeSafe=*/ !aResult );
6300
6301   TPythonDump pyDump;
6302   if (aResult)
6303   {
6304     int lg = anAffected.size();
6305     MESSAGE("lg="<< lg);
6306     SMESH::long_array_var volumeIds = new SMESH::long_array;
6307     volumeIds->length(lg);
6308     SMESH::long_array_var faceIds = new SMESH::long_array;
6309     faceIds->length(lg);
6310     SMESH::long_array_var edgeIds = new SMESH::long_array;
6311     edgeIds->length(lg);
6312     int ivol = 0;
6313     int iface = 0;
6314     int iedge = 0;
6315
6316     TIDSortedElemSet::const_iterator eIt = anAffected.begin();
6317     for (; eIt != anAffected.end(); ++eIt)
6318     {
6319       const SMDS_MeshElement* anElem = *eIt;
6320       if (!anElem)
6321         continue;
6322       int elemId = anElem->GetID();
6323       if (myMesh->GetElementType(elemId, true) == SMDSAbs_Volume)
6324         volumeIds[ivol++] = elemId;
6325       else if (myMesh->GetElementType(elemId, true) == SMDSAbs_Face)
6326         faceIds[iface++] = elemId;
6327       else if (myMesh->GetElementType(elemId, true) == SMDSAbs_Edge)
6328         edgeIds[iedge++] = elemId;
6329     }
6330     volumeIds->length(ivol);
6331     faceIds->length(iface);
6332     edgeIds->length(iedge);
6333
6334     aNewVolumeGroup->Add(volumeIds);
6335     aNewFaceGroup->Add(faceIds);
6336     aNewEdgeGroup->Add(edgeIds);
6337     isVolumeGroup = (aNewVolumeGroup->Size() > 0);
6338     isFaceGroup = (aNewFaceGroup->Size() > 0);
6339     isEdgeGroup = (aNewEdgeGroup->Size() > 0);
6340   }
6341
6342   int nbGroups = 0;
6343   if (isEdgeGroup)   nbGroups++;
6344   if (isFaceGroup)   nbGroups++;
6345   if (isVolumeGroup) nbGroups++;
6346   aListOfGroups->length(nbGroups);
6347
6348   int i = 0;
6349   if (isEdgeGroup)   aListOfGroups[i++] = aNewEdgeGroup._retn();
6350   if (isFaceGroup)   aListOfGroups[i++] = aNewFaceGroup._retn();
6351   if (isVolumeGroup) aListOfGroups[i++] = aNewVolumeGroup._retn();
6352
6353   // Update Python script
6354
6355   pyDump << "[ ";
6356   if (isEdgeGroup)   pyDump << aNewEdgeGroup << ", ";
6357   if (isFaceGroup)   pyDump << aNewFaceGroup << ", ";
6358   if (isVolumeGroup) pyDump << aNewVolumeGroup << ", ";
6359   pyDump << "] = ";
6360   pyDump << this << ".AffectedElemGroupsInRegion( "
6361          << &theElems << ", " << &theNodesNot << ", " << theShape << " )";
6362
6363   return aListOfGroups._retn();
6364
6365   SMESH_CATCH( SMESH::throwCorbaException );
6366   return 0;
6367 }
6368
6369 //================================================================================
6370 /*!
6371   \brief Generated skin mesh (containing 2D cells) from 3D mesh
6372    The created 2D mesh elements based on nodes of free faces of boundary volumes
6373   \return TRUE if operation has been completed successfully, FALSE otherwise
6374 */
6375 //================================================================================
6376
6377 CORBA::Boolean SMESH_MeshEditor_i::Make2DMeshFrom3D()
6378   throw (SALOME::SALOME_Exception)
6379 {
6380   SMESH_TRY;
6381   initData();
6382
6383   bool aResult = getEditor().Make2DMeshFrom3D();
6384
6385   TPythonDump() << "isDone = " << this << ".Make2DMeshFrom3D()";
6386
6387   declareMeshModified( /*isReComputeSafe=*/ !aResult );
6388   return aResult;
6389
6390   SMESH_CATCH( SMESH::throwCorbaException );
6391   return false;
6392 }
6393
6394 //================================================================================
6395 /*!
6396  * \brief Double nodes on shared faces between groups of volumes and create flat elements on demand.
6397  * The list of groups must contain at least two groups. The groups have to be disjoint:
6398  * no common element into two different groups.
6399  * The nodes of the internal faces at the boundaries of the groups are doubled.
6400  * Optionally, the internal faces are replaced by flat elements.
6401  * Triangles are transformed into prisms, and quadrangles into hexahedrons.
6402  * The flat elements are stored in groups of volumes.
6403  * These groups are named according to the position of the group in the list:
6404  * 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.
6405  * 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.
6406  * All the flat elements are gathered into the group named "joints3D" (or "joints2D" in 2D situation).
6407  * The flat element of the multiple junctions between the simple junction are stored in a group named "jointsMultiples".
6408  * \param theDomains - list of groups of volumes
6409  * \param createJointElems - if TRUE, create the elements
6410  * \param onAllBoundaries - if TRUE, the nodes and elements are also created on
6411  *        the boundary between \a theDomains and the rest mesh
6412  * \return TRUE if operation has been completed successfully, FALSE otherwise
6413  */
6414 //================================================================================
6415
6416 CORBA::Boolean
6417 SMESH_MeshEditor_i::DoubleNodesOnGroupBoundaries( const SMESH::ListOfGroups& theDomains,
6418                                                   CORBA::Boolean             createJointElems,
6419                                                   CORBA::Boolean             onAllBoundaries )
6420   throw (SALOME::SALOME_Exception)
6421 {
6422   bool isOK = false;
6423
6424   SMESH_TRY;
6425   initData();
6426
6427   SMESHDS_Mesh* aMeshDS = getMeshDS();
6428
6429   // MESSAGE("theDomains.length = "<<theDomains.length());
6430   if ( theDomains.length() <= 1 && !onAllBoundaries )
6431     THROW_SALOME_CORBA_EXCEPTION("At least 2 groups are required.", SALOME::BAD_PARAM);
6432
6433   vector<TIDSortedElemSet> domains;
6434   domains.resize( theDomains.length() );
6435
6436   for ( int i = 0, n = theDomains.length(); i < n; i++ )
6437   {
6438     SMESH::SMESH_GroupBase_var aGrp = theDomains[ i ];
6439     if ( !CORBA::is_nil( aGrp ) /*&& ( aGrp->GetType() != SMESH::NODE )*/ )
6440     {
6441 //      if ( aGrp->GetType() != SMESH::VOLUME )
6442 //        THROW_SALOME_CORBA_EXCEPTION("Not a volume group", SALOME::BAD_PARAM);
6443       SMESH::long_array_var anIDs = aGrp->GetIDs();
6444       arrayToSet( anIDs, aMeshDS, domains[ i ], SMDSAbs_All );
6445     }
6446   }
6447
6448   isOK = getEditor().DoubleNodesOnGroupBoundaries( domains, createJointElems, onAllBoundaries );
6449   // TODO publish the groups of flat elements in study
6450
6451   declareMeshModified( /*isReComputeSafe=*/ !isOK );
6452
6453   // Update Python script
6454   TPythonDump() << "isDone = " << this << ".DoubleNodesOnGroupBoundaries( " << &theDomains
6455                 << ", " << createJointElems << ", " << onAllBoundaries << " )";
6456
6457   SMESH_CATCH( SMESH::throwCorbaException );
6458
6459   myMesh_i->CreateGroupServants(); // publish created groups if any
6460
6461   return isOK;
6462 }
6463
6464 //================================================================================
6465 /*!
6466  * \brief Double nodes on some external faces and create flat elements.
6467  * Flat elements are mainly used by some types of mechanic calculations.
6468  *
6469  * Each group of the list must be constituted of faces.
6470  * Triangles are transformed in prisms, and quadrangles in hexahedrons.
6471  * @param theGroupsOfFaces - list of groups of faces
6472  * @return TRUE if operation has been completed successfully, FALSE otherwise
6473  */
6474 //================================================================================
6475
6476 CORBA::Boolean
6477 SMESH_MeshEditor_i::CreateFlatElementsOnFacesGroups( const SMESH::ListOfGroups& theGroupsOfFaces )
6478   throw (SALOME::SALOME_Exception)
6479 {
6480   SMESH_TRY;
6481   initData();
6482
6483   SMESHDS_Mesh* aMeshDS = getMeshDS();
6484
6485   vector<TIDSortedElemSet> faceGroups;
6486   faceGroups.clear();
6487
6488   for ( int i = 0, n = theGroupsOfFaces.length(); i < n; i++ )
6489   {
6490     SMESH::SMESH_GroupBase_var aGrp = theGroupsOfFaces[ i ];
6491     if ( !CORBA::is_nil( aGrp ) && ( aGrp->GetType() != SMESH::NODE ) )
6492     {
6493       TIDSortedElemSet faceGroup;
6494       faceGroup.clear();
6495       faceGroups.push_back(faceGroup);
6496       SMESH::long_array_var anIDs = aGrp->GetIDs();
6497       arrayToSet( anIDs, aMeshDS, faceGroups[ i ], SMDSAbs_All );
6498     }
6499   }
6500
6501   bool aResult = getEditor().CreateFlatElementsOnFacesGroups( faceGroups );
6502   // TODO publish the groups of flat elements in study
6503
6504   declareMeshModified( /*isReComputeSafe=*/ !aResult );
6505
6506   // Update Python script
6507   TPythonDump() << this << ".CreateFlatElementsOnFacesGroups( " << &theGroupsOfFaces << " )";
6508   return aResult;
6509
6510   SMESH_CATCH( SMESH::throwCorbaException );
6511   return false;
6512 }
6513
6514 //================================================================================
6515 /*!
6516  *  \brief Identify all the elements around a geom shape, get the faces delimiting
6517  *         the hole.
6518  *
6519  *  Build groups of volume to remove, groups of faces to replace on the skin of the
6520  *  object, groups of faces to remove inside the object, (idem edges).
6521  *  Build ordered list of nodes at the border of each group of faces to replace
6522  *  (to be used to build a geom subshape).
6523  */
6524 //================================================================================
6525
6526 void SMESH_MeshEditor_i::CreateHoleSkin(CORBA::Double                  radius,
6527                                         GEOM::GEOM_Object_ptr          theShape,
6528                                         const char*                    groupName,
6529                                         const SMESH::double_array&     theNodesCoords,
6530                                         SMESH::array_of_long_array_out GroupsOfNodes)
6531   throw (SALOME::SALOME_Exception)
6532 {
6533   SMESH_TRY;
6534
6535   initData();
6536   std::vector<std::vector<int> > aListOfListOfNodes;
6537   ::SMESH_MeshEditor aMeshEditor( myMesh );
6538
6539   theSearchersDeleter.Set( myMesh ); // remove theNodeSearcher if mesh is other
6540   if ( !theNodeSearcher )
6541     theNodeSearcher = SMESH_MeshAlgos::GetNodeSearcher( *getMeshDS() );
6542
6543   vector<double> nodesCoords;
6544   for ( CORBA::ULong i = 0; i < theNodesCoords.length(); i++)
6545   {
6546     nodesCoords.push_back( theNodesCoords[i] );
6547   }
6548
6549   TopoDS_Shape aShape = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape( theShape );
6550   aMeshEditor.CreateHoleSkin(radius, aShape, theNodeSearcher, groupName,
6551                              nodesCoords, aListOfListOfNodes);
6552
6553   GroupsOfNodes = new SMESH::array_of_long_array;
6554   GroupsOfNodes->length( aListOfListOfNodes.size() );
6555   std::vector<std::vector<int> >::iterator llIt = aListOfListOfNodes.begin();
6556   for ( CORBA::Long i = 0; llIt != aListOfListOfNodes.end(); llIt++, i++ )
6557   {
6558     vector<int>& aListOfNodes = *llIt;
6559     vector<int>::iterator lIt = aListOfNodes.begin();;
6560     SMESH::long_array& aGroup = (*GroupsOfNodes)[ i ];
6561     aGroup.length( aListOfNodes.size() );
6562     for ( int j = 0; lIt != aListOfNodes.end(); lIt++, j++ )
6563       aGroup[ j ] = (*lIt);
6564   }
6565   TPythonDump() << "lists_nodes = " << this << ".CreateHoleSkin( "
6566                 << radius << ", "
6567                 << theShape
6568                 << ", '" << groupName << "', "
6569                 << theNodesCoords << " )";
6570
6571   SMESH_CATCH( SMESH::throwCorbaException );
6572 }
6573
6574 // issue 20749 ===================================================================
6575 /*!
6576  * \brief Creates missing boundary elements
6577  *  \param elements - elements whose boundary is to be checked
6578  *  \param dimension - defines type of boundary elements to create
6579  *  \param groupName - a name of group to store created boundary elements in,
6580  *                     "" means not to create the group
6581  *  \param meshName - a name of new mesh to store created boundary elements in,
6582  *                     "" means not to create the new mesh
6583  *  \param toCopyElements - if true, the checked elements will be copied into the new mesh
6584  *  \param toCopyExistingBondary - if true, not only new but also pre-existing
6585  *                                boundary elements will be copied into the new mesh
6586  *  \param group - returns the create group, if any
6587  *  \retval SMESH::SMESH_Mesh - the mesh where elements were added to
6588  */
6589 // ================================================================================
6590
6591 SMESH::SMESH_Mesh_ptr
6592 SMESH_MeshEditor_i::MakeBoundaryMesh(SMESH::SMESH_IDSource_ptr idSource,
6593                                      SMESH::Bnd_Dimension      dim,
6594                                      const char*               groupName,
6595                                      const char*               meshName,
6596                                      CORBA::Boolean            toCopyElements,
6597                                      CORBA::Boolean            toCopyExistingBondary,
6598                                      SMESH::SMESH_Group_out    group)
6599   throw (SALOME::SALOME_Exception)
6600 {
6601   SMESH_TRY;
6602   initData();
6603
6604   if ( dim > SMESH::BND_1DFROM2D )
6605     THROW_SALOME_CORBA_EXCEPTION("Invalid boundary dimension", SALOME::BAD_PARAM);
6606
6607   SMESHDS_Mesh* aMeshDS = getMeshDS();
6608
6609   SMESH::SMESH_Mesh_var mesh_var;
6610   SMESH::SMESH_Group_var group_var;
6611
6612   TPythonDump pyDump;
6613
6614   TIDSortedElemSet elements;
6615   SMDSAbs_ElementType elemType = (dim == SMESH::BND_1DFROM2D) ? SMDSAbs_Face : SMDSAbs_Volume;
6616   if ( idSourceToSet( idSource, aMeshDS, elements, elemType,/*emptyIfIsMesh=*/true ))
6617   {
6618     // mesh to fill in
6619     mesh_var =
6620       strlen(meshName) ? makeMesh(meshName) : SMESH::SMESH_Mesh::_duplicate(myMesh_i->_this());
6621     SMESH_Mesh_i* mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh_var );
6622     // other mesh
6623     SMESH_Mesh* smesh_mesh = (mesh_i==myMesh_i) ? (SMESH_Mesh*)0 : &mesh_i->GetImpl();
6624
6625     // group of new boundary elements
6626     SMESH_Group* smesh_group = 0;
6627     if ( strlen(groupName) )
6628     {
6629       group_var = mesh_i->CreateGroup( SMESH::ElementType(int(elemType)-1),groupName);
6630       if ( SMESH_GroupBase_i* group_i = SMESH::DownCast<SMESH_GroupBase_i*>( group_var ))
6631         smesh_group = group_i->GetSmeshGroup();
6632     }
6633
6634     // do it
6635     getEditor().MakeBoundaryMesh( elements,
6636                                   ::SMESH_MeshEditor::Bnd_Dimension(dim),
6637                                   smesh_group,
6638                                   smesh_mesh,
6639                                   toCopyElements,
6640                                   toCopyExistingBondary);
6641
6642     if ( smesh_mesh )
6643       smesh_mesh->GetMeshDS()->Modified();
6644   }
6645
6646   const char* dimName[] = { "BND_2DFROM3D", "BND_1DFROM3D", "BND_1DFROM2D" };
6647
6648   // result of MakeBoundaryMesh() is a tuple (mesh, group)
6649   if ( mesh_var->_is_nil() )
6650     pyDump << myMesh_i->_this() << ", ";
6651   else
6652     pyDump << mesh_var << ", ";
6653   if ( group_var->_is_nil() )
6654     pyDump << "_NoneGroup = "; // assignment to None is forbiden
6655   else
6656     pyDump << group_var << " = ";
6657   pyDump << this << ".MakeBoundaryMesh( "
6658          << idSource << ", "
6659          << "SMESH." << dimName[int(dim)] << ", "
6660          << "'" << groupName << "', "
6661          << "'" << meshName<< "', "
6662          << toCopyElements << ", "
6663          << toCopyExistingBondary << ")";
6664
6665   group = group_var._retn();
6666   return mesh_var._retn();
6667
6668   SMESH_CATCH( SMESH::throwCorbaException );
6669   return SMESH::SMESH_Mesh::_nil();
6670 }
6671
6672 //================================================================================
6673 /*!
6674  * \brief Creates missing boundary elements
6675  *  \param dimension - defines type of boundary elements to create
6676  *  \param groupName - a name of group to store all boundary elements in,
6677  *    "" means not to create the group
6678  *  \param meshName - a name of a new mesh, which is a copy of the initial 
6679  *    mesh + created boundary elements; "" means not to create the new mesh
6680  *  \param toCopyAll - if true, the whole initial mesh will be copied into
6681  *    the new mesh else only boundary elements will be copied into the new mesh
6682  *  \param groups - optional groups of elements to make boundary around
6683  *  \param mesh - returns the mesh where elements were added to
6684  *  \param group - returns the created group, if any
6685  *  \retval long - number of added boundary elements
6686  */
6687 //================================================================================
6688
6689 CORBA::Long SMESH_MeshEditor_i::MakeBoundaryElements(SMESH::Bnd_Dimension dim,
6690                                                      const char* groupName,
6691                                                      const char* meshName,
6692                                                      CORBA::Boolean toCopyAll,
6693                                                      const SMESH::ListOfIDSources& groups,
6694                                                      SMESH::SMESH_Mesh_out mesh,
6695                                                      SMESH::SMESH_Group_out group)
6696   throw (SALOME::SALOME_Exception)
6697 {
6698   SMESH_TRY;
6699   initData();
6700
6701   if ( dim > SMESH::BND_1DFROM2D )
6702     THROW_SALOME_CORBA_EXCEPTION("Invalid boundary dimension", SALOME::BAD_PARAM);
6703
6704   // separate groups belonging to this and other mesh
6705   SMESH::ListOfIDSources_var groupsOfThisMesh  = new SMESH::ListOfIDSources;
6706   SMESH::ListOfIDSources_var groupsOfOtherMesh = new SMESH::ListOfIDSources;
6707   groupsOfThisMesh ->length( groups.length() );
6708   groupsOfOtherMesh->length( groups.length() );
6709   int nbGroups = 0, nbGroupsOfOtherMesh = 0;
6710   for ( CORBA::ULong i = 0; i < groups.length(); ++i )
6711   {
6712     SMESH::SMESH_Mesh_var m = groups[i]->GetMesh();
6713     if ( myMesh_i != SMESH::DownCast<SMESH_Mesh_i*>( m ))
6714       groupsOfOtherMesh[ nbGroupsOfOtherMesh++ ] = groups[i];
6715     else
6716       groupsOfThisMesh[ nbGroups++ ] = groups[i];
6717     if ( SMESH::DownCast<SMESH_Mesh_i*>( groups[i] ))
6718       THROW_SALOME_CORBA_EXCEPTION("expect a group but recieve a mesh", SALOME::BAD_PARAM);
6719   }
6720   groupsOfThisMesh->length( nbGroups );
6721   groupsOfOtherMesh->length( nbGroupsOfOtherMesh );
6722
6723   int nbAdded = 0;
6724   TPythonDump pyDump;
6725
6726   if ( nbGroupsOfOtherMesh > 0 )
6727   {
6728     // process groups belonging to another mesh
6729     SMESH::SMESH_Mesh_var    otherMesh = groupsOfOtherMesh[0]->GetMesh();
6730     SMESH::SMESH_MeshEditor_var editor = otherMesh->GetMeshEditor();
6731     nbAdded += editor->MakeBoundaryElements( dim, groupName, meshName, toCopyAll,
6732                                              groupsOfOtherMesh, mesh, group );
6733   }
6734
6735   SMESH::SMESH_Mesh_var mesh_var;
6736   SMESH::SMESH_Group_var group_var;
6737
6738   // get mesh to fill
6739   mesh_var = SMESH::SMESH_Mesh::_duplicate( myMesh_i->_this() );
6740   const bool toCopyMesh = ( strlen( meshName ) > 0 );
6741   if ( toCopyMesh )
6742   {
6743     if ( toCopyAll )
6744       mesh_var = SMESH_Gen_i::GetSMESHGen()->CopyMesh(mesh_var,
6745                                                       meshName,
6746                                                       /*toCopyGroups=*/false,
6747                                                       /*toKeepIDs=*/true);
6748     else
6749       mesh_var = makeMesh(meshName);
6750   }
6751   SMESH_Mesh_i* mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh_var );
6752   SMESH_Mesh*  tgtMesh = &mesh_i->GetImpl();
6753
6754   // source mesh
6755   SMESH_Mesh*     srcMesh = ( toCopyMesh && !toCopyAll ) ? myMesh : tgtMesh;
6756   SMESHDS_Mesh* srcMeshDS = srcMesh->GetMeshDS();
6757
6758   // group of boundary elements
6759   SMESH_Group* smesh_group = 0;
6760   SMDSAbs_ElementType elemType = (dim == SMESH::BND_2DFROM3D) ? SMDSAbs_Volume : SMDSAbs_Face;
6761   if ( strlen(groupName) )
6762   {
6763     SMESH::ElementType groupType = SMESH::ElementType( int(elemType)-1 );
6764     group_var = mesh_i->CreateGroup( groupType, groupName );
6765     if ( SMESH_GroupBase_i* group_i = SMESH::DownCast<SMESH_GroupBase_i*>( group_var ))
6766       smesh_group = group_i->GetSmeshGroup();
6767   }
6768
6769   TIDSortedElemSet elements;
6770
6771   if ( groups.length() > 0 )
6772   {
6773     for ( int i = 0; i < nbGroups; ++i )
6774     {
6775       elements.clear();
6776       if ( idSourceToSet( groupsOfThisMesh[i], srcMeshDS, elements, elemType,/*emptyIfIsMesh=*/0 ))
6777       {
6778         SMESH::Bnd_Dimension bdim = 
6779           ( elemType == SMDSAbs_Volume ) ? SMESH::BND_2DFROM3D : SMESH::BND_1DFROM2D;
6780         nbAdded += getEditor().MakeBoundaryMesh( elements,
6781                                                  ::SMESH_MeshEditor::Bnd_Dimension(bdim),
6782                                                  smesh_group,
6783                                                  tgtMesh,
6784                                                  /*toCopyElements=*/false,
6785                                                  /*toCopyExistingBondary=*/srcMesh != tgtMesh,
6786                                                  /*toAddExistingBondary=*/true,
6787                                                  /*aroundElements=*/true);
6788       }
6789     }
6790   }
6791   else
6792   {
6793     nbAdded += getEditor().MakeBoundaryMesh( elements,
6794                                              ::SMESH_MeshEditor::Bnd_Dimension(dim),
6795                                              smesh_group,
6796                                              tgtMesh,
6797                                              /*toCopyElements=*/false,
6798                                              /*toCopyExistingBondary=*/srcMesh != tgtMesh,
6799                                              /*toAddExistingBondary=*/true);
6800   }
6801   tgtMesh->GetMeshDS()->Modified();
6802
6803   const char* dimName[] = { "BND_2DFROM3D", "BND_1DFROM3D", "BND_1DFROM2D" };
6804
6805   // result of MakeBoundaryElements() is a tuple (nb, mesh, group)
6806   pyDump << "nbAdded, ";
6807   if ( mesh_var->_is_nil() )
6808     pyDump << myMesh_i->_this() << ", ";
6809   else
6810     pyDump << mesh_var << ", ";
6811   if ( group_var->_is_nil() )
6812     pyDump << "_NoneGroup = "; // assignment to None is forbiden
6813   else
6814     pyDump << group_var << " = ";
6815   pyDump << this << ".MakeBoundaryElements( "
6816          << "SMESH." << dimName[int(dim)] << ", "
6817          << "'" << groupName << "', "
6818          << "'" << meshName<< "', "
6819          << toCopyAll << ", "
6820          << groups << ")";
6821
6822   mesh  = mesh_var._retn();
6823   group = group_var._retn();
6824   return nbAdded;
6825
6826   SMESH_CATCH( SMESH::throwCorbaException );
6827   return 0;
6828 }