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