Salome HOME
Clean-up deprecated OCCT-related code
[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   {
5550     aModifiedElems = new SMESH::long_array;
5551     aModifiedElems->length( 0 );
5552   }
5553
5554   TPythonDump pyDump; // suppress dump by the next line
5555
5556   bool done = DoubleNodes( aNodes, aModifiedElems );
5557
5558   pyDump << this << ".DoubleNodeGroup( " << theNodes << ", " << theModifiedElems << " )";
5559
5560   return done;
5561
5562   SMESH_CATCH( SMESH::throwCorbaException );
5563   return 0;
5564 }
5565
5566 //================================================================================
5567 /*!
5568  * \brief Creates a hole in a mesh by doubling the nodes of some particular elements.
5569  * Works as DoubleNodeGroup(), but returns a new group with newly created nodes.
5570  * \param theNodes - group of nodes to be doubled.
5571  * \param theModifiedElems - group of elements to be updated.
5572  * \return a new group with newly created nodes
5573  * \sa DoubleNodeGroup()
5574  */
5575 //================================================================================
5576
5577 SMESH::SMESH_Group_ptr
5578 SMESH_MeshEditor_i::DoubleNodeGroupNew( SMESH::SMESH_GroupBase_ptr theNodes,
5579                                         SMESH::SMESH_GroupBase_ptr theModifiedElems )
5580   throw (SALOME::SALOME_Exception)
5581 {
5582   SMESH_TRY;
5583   SMESH::SMESH_Group_var aNewGroup;
5584
5585   if ( CORBA::is_nil( theNodes ) && theNodes->GetType() != SMESH::NODE )
5586     return aNewGroup._retn();
5587
5588   // Duplicate nodes
5589   SMESH::long_array_var aNodes = theNodes->GetListOfID();
5590   SMESH::long_array_var aModifiedElems;
5591   if ( !CORBA::is_nil( theModifiedElems ) )
5592     aModifiedElems = theModifiedElems->GetListOfID();
5593   else {
5594     aModifiedElems = new SMESH::long_array;
5595     aModifiedElems->length( 0 );
5596   }
5597
5598   TPythonDump pyDump; // suppress dump by the next line
5599
5600   bool aResult = DoubleNodes( aNodes, aModifiedElems );
5601   if ( aResult )
5602   {
5603     // Create group with newly created nodes
5604     SMESH::long_array_var anIds = GetLastCreatedNodes();
5605     if (anIds->length() > 0) {
5606       std::string anUnindexedName (theNodes->GetName());
5607       std::string aNewName = generateGroupName(anUnindexedName + "_double");
5608       aNewGroup = myMesh_i->CreateGroup(SMESH::NODE, aNewName.c_str());
5609       aNewGroup->Add(anIds);
5610       pyDump << aNewGroup << " = ";
5611     }
5612   }
5613
5614   pyDump << this << ".DoubleNodeGroupNew( " << theNodes << ", "
5615          << theModifiedElems << " )";
5616
5617   return aNewGroup._retn();
5618
5619   SMESH_CATCH( SMESH::throwCorbaException );
5620   return 0;
5621 }
5622
5623 //================================================================================
5624 /*!
5625   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5626   This method provided for convenience works as DoubleNodes() described above.
5627   \param theNodes - list of groups of nodes to be doubled
5628   \param theModifiedElems - list of groups of elements to be updated.
5629   \return TRUE if operation has been completed successfully, FALSE otherwise
5630   \sa DoubleNode(), DoubleNodeGroup(), DoubleNodes()
5631 */
5632 //================================================================================
5633
5634 CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeGroups(const SMESH::ListOfGroups& theNodes,
5635                                                     const SMESH::ListOfGroups& theModifiedElems )
5636   throw (SALOME::SALOME_Exception)
5637 {
5638   SMESH_TRY;
5639   initData();
5640
5641   std::list< int > aNodes;
5642   int i, n, j, m;
5643   for ( i = 0, n = theNodes.length(); i < n; i++ )
5644   {
5645     SMESH::SMESH_GroupBase_var aGrp = theNodes[ i ];
5646     if ( !CORBA::is_nil( aGrp ) && aGrp->GetType() == SMESH::NODE )
5647     {
5648       SMESH::long_array_var aCurr = aGrp->GetListOfID();
5649       for ( j = 0, m = aCurr->length(); j < m; j++ )
5650         aNodes.push_back( aCurr[ j ] );
5651     }
5652   }
5653
5654   std::list< int > anElems;
5655   for ( i = 0, n = theModifiedElems.length(); i < n; i++ )
5656   {
5657     SMESH::SMESH_GroupBase_var aGrp = theModifiedElems[ i ];
5658     if ( !CORBA::is_nil( aGrp ) && aGrp->GetType() != SMESH::NODE )
5659     {
5660       SMESH::long_array_var aCurr = aGrp->GetListOfID();
5661       for ( j = 0, m = aCurr->length(); j < m; j++ )
5662         anElems.push_back( aCurr[ j ] );
5663     }
5664   }
5665
5666   bool aResult = getEditor().DoubleNodes( aNodes, anElems );
5667
5668   declareMeshModified( /*isReComputeSafe=*/false );
5669
5670   TPythonDump() << this << ".DoubleNodeGroups( " << theNodes << ", " << theModifiedElems << " )";
5671
5672   return aResult;
5673
5674   SMESH_CATCH( SMESH::throwCorbaException );
5675   return 0;
5676 }
5677
5678 //================================================================================
5679 /*!
5680  * \brief Creates a hole in a mesh by doubling the nodes of some particular elements.
5681  * Works as DoubleNodeGroups(), but returns a new group with newly created nodes.
5682  * \param theNodes - group of nodes to be doubled.
5683  * \param theModifiedElems - group of elements to be updated.
5684  * \return a new group with newly created nodes
5685  * \sa DoubleNodeGroups()
5686  */
5687 //================================================================================
5688
5689 SMESH::SMESH_Group_ptr
5690 SMESH_MeshEditor_i::DoubleNodeGroupsNew( const SMESH::ListOfGroups& theNodes,
5691                                          const SMESH::ListOfGroups& theModifiedElems )
5692   throw (SALOME::SALOME_Exception)
5693 {
5694   SMESH::SMESH_Group_var aNewGroup;
5695
5696   TPythonDump pyDump; // suppress dump by the next line
5697
5698   bool aResult = DoubleNodeGroups( theNodes, theModifiedElems );
5699
5700   if ( aResult )
5701   {
5702     // Create group with newly created nodes
5703     SMESH::long_array_var anIds = GetLastCreatedNodes();
5704     if (anIds->length() > 0) {
5705       std::string anUnindexedName (theNodes[0]->GetName());
5706       std::string aNewName = generateGroupName(anUnindexedName + "_double");
5707       aNewGroup = myMesh_i->CreateGroup(SMESH::NODE, aNewName.c_str());
5708       aNewGroup->Add(anIds);
5709       pyDump << aNewGroup << " = ";
5710     }
5711   }
5712
5713   pyDump << this << ".DoubleNodeGroupsNew( " << theNodes << ", "
5714          << theModifiedElems << " )";
5715
5716   return aNewGroup._retn();
5717 }
5718
5719
5720 //================================================================================
5721 /*!
5722   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5723   \param theElems - the list of elements (edges or faces) to be replicated
5724   The nodes for duplication could be found from these elements
5725   \param theNodesNot - list of nodes to NOT replicate
5726   \param theAffectedElems - the list of elements (cells and edges) to which the
5727   replicated nodes should be associated to.
5728   \return TRUE if operation has been completed successfully, FALSE otherwise
5729   \sa DoubleNodeGroup(), DoubleNodeGroups()
5730 */
5731 //================================================================================
5732
5733 CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeElem( const SMESH::long_array& theElems,
5734                                                    const SMESH::long_array& theNodesNot,
5735                                                    const SMESH::long_array& theAffectedElems )
5736   throw (SALOME::SALOME_Exception)
5737 {
5738   SMESH_TRY;
5739   initData();
5740
5741   SMESHDS_Mesh* aMeshDS = getMeshDS();
5742   TIDSortedElemSet anElems, aNodes, anAffected;
5743   arrayToSet(theElems, aMeshDS, anElems, SMDSAbs_All);
5744   arrayToSet(theNodesNot, aMeshDS, aNodes, SMDSAbs_Node);
5745   arrayToSet(theAffectedElems, aMeshDS, anAffected, SMDSAbs_All);
5746
5747   bool aResult = getEditor().DoubleNodes( anElems, aNodes, anAffected );
5748
5749   // Update Python script
5750   TPythonDump() << this << ".DoubleNodeElem( " << theElems << ", "
5751                 << theNodesNot << ", " << theAffectedElems << " )";
5752
5753   declareMeshModified( /*isReComputeSafe=*/false );
5754   return aResult;
5755
5756   SMESH_CATCH( SMESH::throwCorbaException );
5757   return 0;
5758 }
5759
5760 //================================================================================
5761 /*!
5762   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5763   \param theElems - the list of elements (edges or faces) to be replicated
5764   The nodes for duplication could be found from these elements
5765   \param theNodesNot - list of nodes to NOT replicate
5766   \param theShape - shape to detect affected elements (element which geometric center
5767   located on or inside shape).
5768   The replicated nodes should be associated to affected elements.
5769   \return TRUE if operation has been completed successfully, FALSE otherwise
5770   \sa DoubleNodeGroupInRegion(), DoubleNodeGroupsInRegion()
5771 */
5772 //================================================================================
5773
5774 CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeElemInRegion ( const SMESH::long_array& theElems,
5775                                                             const SMESH::long_array& theNodesNot,
5776                                                             GEOM::GEOM_Object_ptr    theShape )
5777   throw (SALOME::SALOME_Exception)
5778 {
5779   SMESH_TRY;
5780   initData();
5781
5782
5783   SMESHDS_Mesh* aMeshDS = getMeshDS();
5784   TIDSortedElemSet anElems, aNodes;
5785   arrayToSet(theElems, aMeshDS, anElems, SMDSAbs_All);
5786   arrayToSet(theNodesNot, aMeshDS, aNodes, SMDSAbs_Node);
5787
5788   TopoDS_Shape aShape = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape( theShape );
5789   bool aResult = getEditor().DoubleNodesInRegion( anElems, aNodes, aShape );
5790
5791   // Update Python script
5792   TPythonDump() << "isDone = " << this << ".DoubleNodeElemInRegion( " << theElems << ", "
5793                 << theNodesNot << ", " << theShape << " )";
5794
5795   declareMeshModified( /*isReComputeSafe=*/false );
5796   return aResult;
5797
5798   SMESH_CATCH( SMESH::throwCorbaException );
5799   return 0;
5800 }
5801
5802 //================================================================================
5803 /*!
5804   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5805   \param theElems - group of of elements (edges or faces) to be replicated
5806   \param theNodesNot - group of nodes not to replicated
5807   \param theAffectedElems - group of elements to which the replicated nodes
5808   should be associated to.
5809   \return TRUE if operation has been completed successfully, FALSE otherwise
5810   \sa DoubleNodes(), DoubleNodeGroups()
5811 */
5812 //================================================================================
5813
5814 CORBA::Boolean
5815 SMESH_MeshEditor_i::DoubleNodeElemGroup(SMESH::SMESH_GroupBase_ptr theElems,
5816                                         SMESH::SMESH_GroupBase_ptr theNodesNot,
5817                                         SMESH::SMESH_GroupBase_ptr theAffectedElems)
5818   throw (SALOME::SALOME_Exception)
5819 {
5820   SMESH_TRY;
5821   if ( CORBA::is_nil( theElems ) && theElems->GetType() == SMESH::NODE )
5822     return false;
5823
5824   initData();
5825
5826
5827   SMESHDS_Mesh* aMeshDS = getMeshDS();
5828   TIDSortedElemSet anElems, aNodes, anAffected;
5829   idSourceToSet( theElems, aMeshDS, anElems, SMDSAbs_All );
5830   idSourceToSet( theNodesNot, aMeshDS, aNodes, SMDSAbs_Node );
5831   idSourceToSet( theAffectedElems, aMeshDS, anAffected, SMDSAbs_All );
5832
5833   bool aResult = getEditor().DoubleNodes( anElems, aNodes, anAffected );
5834
5835   // Update Python script
5836   TPythonDump() << "isDone = " << this << ".DoubleNodeElemGroup( " << theElems << ", "
5837                 << theNodesNot << ", " << theAffectedElems << " )";
5838
5839   declareMeshModified( /*isReComputeSafe=*/false );
5840   return aResult;
5841
5842   SMESH_CATCH( SMESH::throwCorbaException );
5843   return 0;
5844 }
5845
5846 //================================================================================
5847 /*!
5848  * \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5849  * Works as DoubleNodeElemGroup(), but returns a new group with newly created elements.
5850  * \param theElems - group of of elements (edges or faces) to be replicated
5851  * \param theNodesNot - group of nodes not to replicated
5852  * \param theAffectedElems - group of elements to which the replicated nodes
5853  *        should be associated to.
5854  * \return a new group with newly created elements
5855  * \sa DoubleNodeElemGroup()
5856  */
5857 //================================================================================
5858
5859 SMESH::SMESH_Group_ptr
5860 SMESH_MeshEditor_i::DoubleNodeElemGroupNew(SMESH::SMESH_GroupBase_ptr theElems,
5861                                            SMESH::SMESH_GroupBase_ptr theNodesNot,
5862                                            SMESH::SMESH_GroupBase_ptr theAffectedElems)
5863   throw (SALOME::SALOME_Exception)
5864 {
5865   TPythonDump pyDump;
5866   SMESH::ListOfGroups_var twoGroups = DoubleNodeElemGroup2New( theElems,
5867                                                                theNodesNot,
5868                                                                theAffectedElems,
5869                                                                true, false );
5870   SMESH::SMESH_GroupBase_var baseGroup = twoGroups[0].in();
5871   SMESH::SMESH_Group_var     elemGroup = SMESH::SMESH_Group::_narrow( baseGroup );
5872
5873   pyDump << elemGroup << " = " << this << ".DoubleNodeElemGroupNew( "
5874          << theElems         << ", "
5875          << theNodesNot      << ", "
5876          << theAffectedElems << " )";
5877
5878   return elemGroup._retn();
5879 }
5880
5881 //================================================================================
5882 /*!
5883  * \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5884  * Works as DoubleNodeElemGroup(), but returns a new group with newly created elements.
5885  * \param theElems - group of of elements (edges or faces) to be replicated
5886  * \param theNodesNot - group of nodes not to replicated
5887  * \param theAffectedElems - group of elements to which the replicated nodes
5888  *        should be associated to.
5889  * \return a new group with newly created elements
5890  * \sa DoubleNodeElemGroup()
5891  */
5892 //================================================================================
5893
5894 SMESH::ListOfGroups*
5895 SMESH_MeshEditor_i::DoubleNodeElemGroup2New(SMESH::SMESH_GroupBase_ptr theElems,
5896                                             SMESH::SMESH_GroupBase_ptr theNodesNot,
5897                                             SMESH::SMESH_GroupBase_ptr theAffectedElems,
5898                                             CORBA::Boolean             theElemGroupNeeded,
5899                                             CORBA::Boolean             theNodeGroupNeeded)
5900   throw (SALOME::SALOME_Exception)
5901 {
5902   SMESH_TRY;
5903   SMESH::SMESH_Group_var aNewElemGroup, aNewNodeGroup;
5904   SMESH::ListOfGroups_var aTwoGroups = new SMESH::ListOfGroups();
5905   aTwoGroups->length( 2 );
5906
5907   if ( CORBA::is_nil( theElems ) && theElems->GetType() == SMESH::NODE )
5908     return aTwoGroups._retn();
5909
5910   initData();
5911
5912
5913   SMESHDS_Mesh* aMeshDS = getMeshDS();
5914   TIDSortedElemSet anElems, aNodes, anAffected;
5915   idSourceToSet( theElems, aMeshDS, anElems, SMDSAbs_All );
5916   idSourceToSet( theNodesNot, aMeshDS, aNodes, SMDSAbs_Node );
5917   idSourceToSet( theAffectedElems, aMeshDS, anAffected, SMDSAbs_All );
5918
5919
5920   bool aResult = getEditor().DoubleNodes( anElems, aNodes, anAffected );
5921
5922   declareMeshModified( /*isReComputeSafe=*/ !aResult );
5923
5924   TPythonDump pyDump;
5925
5926   if ( aResult )
5927   {
5928     // Create group with newly created elements
5929     CORBA::String_var elemGroupName = theElems->GetName();
5930     std::string aNewName = generateGroupName( std::string(elemGroupName.in()) + "_double");
5931     if ( !getEditor().GetLastCreatedElems().IsEmpty() && theElemGroupNeeded )
5932     {
5933       SMESH::long_array_var anIds = GetLastCreatedElems();
5934       SMESH::ElementType aGroupType = myMesh_i->GetElementType(anIds[0], true);
5935       aNewElemGroup = myMesh_i->CreateGroup(aGroupType, aNewName.c_str());
5936       aNewElemGroup->Add(anIds);
5937     }
5938     if ( !getEditor().GetLastCreatedNodes().IsEmpty() && theNodeGroupNeeded )
5939     {
5940       SMESH::long_array_var anIds = GetLastCreatedNodes();
5941       aNewNodeGroup = myMesh_i->CreateGroup(SMESH::NODE, aNewName.c_str());
5942       aNewNodeGroup->Add(anIds);
5943     }
5944   }
5945
5946   // Update Python script
5947
5948   pyDump << "[ ";
5949   if ( aNewElemGroup->_is_nil() ) pyDump << "nothing, ";
5950   else                            pyDump << aNewElemGroup << ", ";
5951   if ( aNewNodeGroup->_is_nil() ) pyDump << "nothing ] = ";
5952   else                            pyDump << aNewNodeGroup << " ] = ";
5953
5954   pyDump << this << ".DoubleNodeElemGroup2New( " << theElems << ", "
5955          << theNodesNot        << ", "
5956          << theAffectedElems   << ", "
5957          << theElemGroupNeeded << ", "
5958          << theNodeGroupNeeded <<" )";
5959
5960   aTwoGroups[0] = aNewElemGroup._retn();
5961   aTwoGroups[1] = aNewNodeGroup._retn();
5962   return aTwoGroups._retn();
5963
5964   SMESH_CATCH( SMESH::throwCorbaException );
5965   return 0;
5966 }
5967
5968 //================================================================================
5969 /*!
5970   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5971   \param theElems - group of of elements (edges or faces) to be replicated
5972   \param theNodesNot - group of nodes not to replicated
5973   \param theShape - shape to detect affected elements (element which geometric center
5974   located on or inside shape).
5975   The replicated nodes should be associated to affected elements.
5976   \return TRUE if operation has been completed successfully, FALSE otherwise
5977   \sa DoubleNodesInRegion(), DoubleNodeGroupsInRegion()
5978 */
5979 //================================================================================
5980
5981 CORBA::Boolean
5982 SMESH_MeshEditor_i::DoubleNodeElemGroupInRegion(SMESH::SMESH_GroupBase_ptr theElems,
5983                                                 SMESH::SMESH_GroupBase_ptr theNodesNot,
5984                                                 GEOM::GEOM_Object_ptr      theShape )
5985   throw (SALOME::SALOME_Exception)
5986 {
5987   SMESH_TRY;
5988   if ( CORBA::is_nil( theElems ) && theElems->GetType() == SMESH::NODE )
5989     return false;
5990
5991   initData();
5992
5993
5994   SMESHDS_Mesh* aMeshDS = getMeshDS();
5995   TIDSortedElemSet anElems, aNodes, anAffected;
5996   idSourceToSet( theElems, aMeshDS, anElems, SMDSAbs_All );
5997   idSourceToSet( theNodesNot, aMeshDS, aNodes, SMDSAbs_Node );
5998
5999   TopoDS_Shape aShape = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape( theShape );
6000   bool aResult = getEditor().DoubleNodesInRegion( anElems, aNodes, aShape );
6001
6002
6003   declareMeshModified( /*isReComputeSafe=*/ !aResult );
6004
6005   // Update Python script
6006   TPythonDump() << "isDone = " << this << ".DoubleNodeElemGroupInRegion( " << theElems << ", "
6007                 << theNodesNot << ", " << theShape << " )";
6008   return aResult;
6009
6010   SMESH_CATCH( SMESH::throwCorbaException );
6011   return 0;
6012 }
6013
6014 //================================================================================
6015 /*!
6016  * \brief Re-load elements from a list of groups into a TIDSortedElemSet
6017  *  \param [in] theGrpList - groups
6018  *  \param [in] theMeshDS -  mesh
6019  *  \param [out] theElemSet - set of elements
6020  *  \param [in] theIsNodeGrp - is \a theGrpList includes goups of nodes
6021  */
6022 //================================================================================
6023
6024 static void listOfGroupToSet(const SMESH::ListOfGroups& theGrpList,
6025                              SMESHDS_Mesh*              theMeshDS,
6026                              TIDSortedElemSet&          theElemSet,
6027                              const bool                 theIsNodeGrp)
6028 {
6029   for ( int i = 0, n = theGrpList.length(); i < n; i++ )
6030   {
6031     SMESH::SMESH_GroupBase_var aGrp = theGrpList[ i ];
6032     if ( !CORBA::is_nil( aGrp ) && (theIsNodeGrp ? aGrp->GetType() == SMESH::NODE
6033                                     : aGrp->GetType() != SMESH::NODE ) )
6034     {
6035       SMESH::long_array_var anIDs = aGrp->GetIDs();
6036       arrayToSet( anIDs, theMeshDS, theElemSet, theIsNodeGrp ? SMDSAbs_Node : SMDSAbs_All );
6037     }
6038   }
6039 }
6040
6041 //================================================================================
6042 /*!
6043   \brief Creates a hole in a mesh by doubling the nodes of some particular elements.
6044   This method provided for convenience works as DoubleNodes() described above.
6045   \param theElems - list of groups of elements (edges or faces) to be replicated
6046   \param theNodesNot - list of groups of nodes not to replicated
6047   \param theAffectedElems - group of elements to which the replicated nodes
6048   should be associated to.
6049   \return TRUE if operation has been completed successfully, FALSE otherwise
6050   \sa DoubleNodeGroup(), DoubleNodes(), DoubleNodeElemGroupsNew()
6051 */
6052 //================================================================================
6053
6054 CORBA::Boolean
6055 SMESH_MeshEditor_i::DoubleNodeElemGroups(const SMESH::ListOfGroups& theElems,
6056                                          const SMESH::ListOfGroups& theNodesNot,
6057                                          const SMESH::ListOfGroups& theAffectedElems)
6058   throw (SALOME::SALOME_Exception)
6059 {
6060   SMESH_TRY;
6061   initData();
6062
6063
6064   SMESHDS_Mesh* aMeshDS = getMeshDS();
6065   TIDSortedElemSet anElems, aNodes, anAffected;
6066   listOfGroupToSet(theElems, aMeshDS, anElems, false );
6067   listOfGroupToSet(theNodesNot, aMeshDS, aNodes, true );
6068   listOfGroupToSet(theAffectedElems, aMeshDS, anAffected, false );
6069
6070   bool aResult = getEditor().DoubleNodes( anElems, aNodes, anAffected );
6071
6072   // Update Python script
6073   TPythonDump() << "isDone = " << this << ".DoubleNodeElemGroups( " << &theElems << ", "
6074                 << &theNodesNot << ", " << &theAffectedElems << " )";
6075
6076   declareMeshModified( /*isReComputeSafe=*/false );
6077   return aResult;
6078
6079   SMESH_CATCH( SMESH::throwCorbaException );
6080   return 0;
6081 }
6082
6083 //================================================================================
6084 /*!
6085  * \brief Creates a hole in a mesh by doubling the nodes of some particular elements
6086  * Works as DoubleNodeElemGroups(), but returns a new group with newly created elements.
6087   \param theElems - list of groups of elements (edges or faces) to be replicated
6088   \param theNodesNot - list of groups of nodes not to replicated
6089   \param theAffectedElems - group of elements to which the replicated nodes
6090   should be associated to.
6091  * \return a new group with newly created elements
6092  * \sa DoubleNodeElemGroups()
6093  */
6094 //================================================================================
6095
6096 SMESH::SMESH_Group_ptr
6097 SMESH_MeshEditor_i::DoubleNodeElemGroupsNew(const SMESH::ListOfGroups& theElems,
6098                                             const SMESH::ListOfGroups& theNodesNot,
6099                                             const SMESH::ListOfGroups& theAffectedElems)
6100   throw (SALOME::SALOME_Exception)
6101 {
6102   TPythonDump pyDump;
6103   SMESH::ListOfGroups_var twoGroups = DoubleNodeElemGroups2New( theElems,
6104                                                                 theNodesNot,
6105                                                                 theAffectedElems,
6106                                                                 true, false );
6107   SMESH::SMESH_GroupBase_var baseGroup = twoGroups[0].in();
6108   SMESH::SMESH_Group_var     elemGroup = SMESH::SMESH_Group::_narrow( baseGroup );
6109
6110   pyDump << elemGroup << " = " << this << ".DoubleNodeElemGroupsNew( "
6111          << theElems         << ", "
6112          << theNodesNot      << ", "
6113          << theAffectedElems << " )";
6114
6115   return elemGroup._retn();
6116 }
6117
6118 //================================================================================
6119 /*!
6120  * \brief Creates a hole in a mesh by doubling the nodes of some particular elements
6121  * Works as DoubleNodeElemGroups(), but returns a new group with newly created elements.
6122   \param theElems - list of groups of elements (edges or faces) to be replicated
6123   \param theNodesNot - list of groups of nodes not to replicated
6124   \param theAffectedElems - group of elements to which the replicated nodes
6125   should be associated to.
6126  * \return a new group with newly created elements
6127  * \sa DoubleNodeElemGroups()
6128  */
6129 //================================================================================
6130
6131 SMESH::ListOfGroups*
6132 SMESH_MeshEditor_i::DoubleNodeElemGroups2New(const SMESH::ListOfGroups& theElems,
6133                                              const SMESH::ListOfGroups& theNodesNot,
6134                                              const SMESH::ListOfGroups& theAffectedElems,
6135                                              CORBA::Boolean             theElemGroupNeeded,
6136                                              CORBA::Boolean             theNodeGroupNeeded)
6137   throw (SALOME::SALOME_Exception)
6138 {
6139   SMESH_TRY;
6140   SMESH::SMESH_Group_var aNewElemGroup, aNewNodeGroup;
6141   SMESH::ListOfGroups_var aTwoGroups = new SMESH::ListOfGroups();
6142   aTwoGroups->length( 2 );
6143   
6144   initData();
6145
6146
6147   SMESHDS_Mesh* aMeshDS = getMeshDS();
6148   TIDSortedElemSet anElems, aNodes, anAffected;
6149   listOfGroupToSet(theElems, aMeshDS, anElems, false );
6150   listOfGroupToSet(theNodesNot, aMeshDS, aNodes, true );
6151   listOfGroupToSet(theAffectedElems, aMeshDS, anAffected, false );
6152
6153   bool aResult = getEditor().DoubleNodes( anElems, aNodes, anAffected );
6154
6155   declareMeshModified( /*isReComputeSafe=*/ !aResult );
6156
6157   TPythonDump pyDump;
6158   if ( aResult )
6159   {
6160     // Create group with newly created elements
6161     CORBA::String_var elemGroupName = theElems[0]->GetName();
6162     std::string aNewName = generateGroupName( std::string(elemGroupName.in()) + "_double");
6163     if ( !getEditor().GetLastCreatedElems().IsEmpty() && theElemGroupNeeded )
6164     {
6165       SMESH::long_array_var anIds = GetLastCreatedElems();
6166       SMESH::ElementType aGroupType = myMesh_i->GetElementType(anIds[0], true);
6167       aNewElemGroup = myMesh_i->CreateGroup(aGroupType, aNewName.c_str());
6168       aNewElemGroup->Add(anIds);
6169     }
6170     if ( !getEditor().GetLastCreatedNodes().IsEmpty() && theNodeGroupNeeded )
6171     {
6172       SMESH::long_array_var anIds = GetLastCreatedNodes();
6173       aNewNodeGroup = myMesh_i->CreateGroup(SMESH::NODE, aNewName.c_str());
6174       aNewNodeGroup->Add(anIds);
6175     }
6176   }
6177
6178   // Update Python script
6179
6180   pyDump << "[ ";
6181   if ( aNewElemGroup->_is_nil() ) pyDump << "nothing, ";
6182   else                            pyDump << aNewElemGroup << ", ";
6183   if ( aNewNodeGroup->_is_nil() ) pyDump << "nothing ] = ";
6184   else                            pyDump << aNewNodeGroup << " ] = ";
6185
6186   pyDump << this << ".DoubleNodeElemGroups2New( " << &theElems << ", "
6187          << &theNodesNot       << ", "
6188          << &theAffectedElems  << ", "
6189          << theElemGroupNeeded << ", "
6190          << theNodeGroupNeeded << " )";
6191
6192   aTwoGroups[0] = aNewElemGroup._retn();
6193   aTwoGroups[1] = aNewNodeGroup._retn();
6194   return aTwoGroups._retn();
6195
6196   SMESH_CATCH( SMESH::throwCorbaException );
6197   return 0;
6198 }
6199
6200 //================================================================================
6201 /*!
6202   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
6203   This method provided for convenience works as DoubleNodes() described above.
6204   \param theElems - list of groups of elements (edges or faces) to be replicated
6205   \param theNodesNot - list of groups of nodes not to replicated
6206   \param theShape - shape to detect affected elements (element which geometric center
6207   located on or inside shape).
6208   The replicated nodes should be associated to affected elements.
6209   \return TRUE if operation has been completed successfully, FALSE otherwise
6210   \sa DoubleNodeGroupInRegion(), DoubleNodesInRegion()
6211 */
6212 //================================================================================
6213
6214 CORBA::Boolean
6215 SMESH_MeshEditor_i::DoubleNodeElemGroupsInRegion(const SMESH::ListOfGroups& theElems,
6216                                                  const SMESH::ListOfGroups& theNodesNot,
6217                                                  GEOM::GEOM_Object_ptr      theShape )
6218   throw (SALOME::SALOME_Exception)
6219 {
6220   SMESH_TRY;
6221   initData();
6222
6223
6224   SMESHDS_Mesh* aMeshDS = getMeshDS();
6225   TIDSortedElemSet anElems, aNodes;
6226   listOfGroupToSet(theElems, aMeshDS, anElems,false );
6227   listOfGroupToSet(theNodesNot, aMeshDS, aNodes, true );
6228
6229   TopoDS_Shape aShape = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape( theShape );
6230   bool aResult = getEditor().DoubleNodesInRegion( anElems, aNodes, aShape );
6231
6232   // Update Python script
6233   TPythonDump() << "isDone = " << this << ".DoubleNodeElemGroupsInRegion( " << &theElems << ", "
6234                 << &theNodesNot << ", " << theShape << " )";
6235
6236   declareMeshModified( /*isReComputeSafe=*/ !aResult );
6237   return aResult;
6238
6239   SMESH_CATCH( SMESH::throwCorbaException );
6240   return 0;
6241 }
6242
6243 //================================================================================
6244 /*!
6245   \brief Identify the elements that will be affected by node duplication (actual
6246          duplication is not performed.
6247   This method is the first step of DoubleNodeElemGroupsInRegion.
6248   \param theElems - list of groups of elements (edges or faces) to be replicated
6249   \param theNodesNot - list of groups of nodes not to replicated
6250   \param theShape - shape to detect affected elements (element which geometric center
6251          located on or inside shape).
6252          The replicated nodes should be associated to affected elements.
6253   \return groups of affected elements
6254   \sa DoubleNodeElemGroupsInRegion()
6255 */
6256 //================================================================================
6257 SMESH::ListOfGroups*
6258 SMESH_MeshEditor_i::AffectedElemGroupsInRegion( const SMESH::ListOfGroups& theElems,
6259                                                 const SMESH::ListOfGroups& theNodesNot,
6260                                                 GEOM::GEOM_Object_ptr      theShape )
6261   throw (SALOME::SALOME_Exception)
6262 {
6263   SMESH_TRY;
6264   SMESH::ListOfGroups_var aListOfGroups = new SMESH::ListOfGroups();
6265   bool isEdgeGroup = false;
6266   bool isFaceGroup = false;
6267   bool isVolumeGroup = false;
6268   SMESH::SMESH_Group_var aNewEdgeGroup = myMesh_i->CreateGroup(SMESH::EDGE, "affectedEdges");
6269   SMESH::SMESH_Group_var aNewFaceGroup = myMesh_i->CreateGroup(SMESH::FACE, "affectedFaces");
6270   SMESH::SMESH_Group_var aNewVolumeGroup = myMesh_i->CreateGroup(SMESH::VOLUME, "affectedVolumes");
6271
6272   initData();
6273
6274   ::SMESH_MeshEditor aMeshEditor(myMesh);
6275
6276   SMESHDS_Mesh* aMeshDS = getMeshDS();
6277   TIDSortedElemSet anElems, aNodes;
6278   listOfGroupToSet(theElems, aMeshDS, anElems, false);
6279   listOfGroupToSet(theNodesNot, aMeshDS, aNodes, true);
6280
6281   TopoDS_Shape aShape = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape(theShape);
6282   TIDSortedElemSet anAffected;
6283   bool aResult = aMeshEditor.AffectedElemGroupsInRegion(anElems, aNodes, aShape, anAffected);
6284
6285
6286   declareMeshModified( /*isReComputeSafe=*/ !aResult );
6287
6288   TPythonDump pyDump;
6289   if (aResult)
6290   {
6291     int lg = anAffected.size();
6292     SMESH::long_array_var volumeIds = new SMESH::long_array;
6293     volumeIds->length(lg);
6294     SMESH::long_array_var faceIds = new SMESH::long_array;
6295     faceIds->length(lg);
6296     SMESH::long_array_var edgeIds = new SMESH::long_array;
6297     edgeIds->length(lg);
6298     int ivol = 0;
6299     int iface = 0;
6300     int iedge = 0;
6301
6302     TIDSortedElemSet::const_iterator eIt = anAffected.begin();
6303     for (; eIt != anAffected.end(); ++eIt)
6304     {
6305       const SMDS_MeshElement* anElem = *eIt;
6306       if (!anElem)
6307         continue;
6308       int elemId = anElem->GetID();
6309       if (myMesh->GetElementType(elemId, true) == SMDSAbs_Volume)
6310         volumeIds[ivol++] = elemId;
6311       else if (myMesh->GetElementType(elemId, true) == SMDSAbs_Face)
6312         faceIds[iface++] = elemId;
6313       else if (myMesh->GetElementType(elemId, true) == SMDSAbs_Edge)
6314         edgeIds[iedge++] = elemId;
6315     }
6316     volumeIds->length(ivol);
6317     faceIds->length(iface);
6318     edgeIds->length(iedge);
6319
6320     aNewVolumeGroup->Add(volumeIds);
6321     aNewFaceGroup->Add(faceIds);
6322     aNewEdgeGroup->Add(edgeIds);
6323     isVolumeGroup = (aNewVolumeGroup->Size() > 0);
6324     isFaceGroup = (aNewFaceGroup->Size() > 0);
6325     isEdgeGroup = (aNewEdgeGroup->Size() > 0);
6326   }
6327
6328   int nbGroups = 0;
6329   if (isEdgeGroup)   nbGroups++;
6330   if (isFaceGroup)   nbGroups++;
6331   if (isVolumeGroup) nbGroups++;
6332   aListOfGroups->length(nbGroups);
6333
6334   int i = 0;
6335   if (isEdgeGroup)   aListOfGroups[i++] = aNewEdgeGroup._retn();
6336   if (isFaceGroup)   aListOfGroups[i++] = aNewFaceGroup._retn();
6337   if (isVolumeGroup) aListOfGroups[i++] = aNewVolumeGroup._retn();
6338
6339   // Update Python script
6340
6341   pyDump << "[ ";
6342   if (isEdgeGroup)   pyDump << aNewEdgeGroup << ", ";
6343   if (isFaceGroup)   pyDump << aNewFaceGroup << ", ";
6344   if (isVolumeGroup) pyDump << aNewVolumeGroup << ", ";
6345   pyDump << "] = ";
6346   pyDump << this << ".AffectedElemGroupsInRegion( "
6347          << &theElems << ", " << &theNodesNot << ", " << theShape << " )";
6348
6349   return aListOfGroups._retn();
6350
6351   SMESH_CATCH( SMESH::throwCorbaException );
6352   return 0;
6353 }
6354
6355 //================================================================================
6356 /*!
6357   \brief Generated skin mesh (containing 2D cells) from 3D mesh
6358    The created 2D mesh elements based on nodes of free faces of boundary volumes
6359   \return TRUE if operation has been completed successfully, FALSE otherwise
6360 */
6361 //================================================================================
6362
6363 CORBA::Boolean SMESH_MeshEditor_i::Make2DMeshFrom3D()
6364   throw (SALOME::SALOME_Exception)
6365 {
6366   SMESH_TRY;
6367   initData();
6368
6369   bool aResult = getEditor().Make2DMeshFrom3D();
6370
6371   TPythonDump() << "isDone = " << this << ".Make2DMeshFrom3D()";
6372
6373   declareMeshModified( /*isReComputeSafe=*/ !aResult );
6374   return aResult;
6375
6376   SMESH_CATCH( SMESH::throwCorbaException );
6377   return false;
6378 }
6379
6380 //================================================================================
6381 /*!
6382  * \brief Double nodes on shared faces between groups of volumes and create flat elements on demand.
6383  * The list of groups must contain at least two groups. The groups have to be disjoint:
6384  * no common element into two different groups.
6385  * The nodes of the internal faces at the boundaries of the groups are doubled.
6386  * Optionally, the internal faces are replaced by flat elements.
6387  * Triangles are transformed into prisms, and quadrangles into hexahedrons.
6388  * The flat elements are stored in groups of volumes.
6389  * These groups are named according to the position of the group in the list:
6390  * 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.
6391  * 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.
6392  * All the flat elements are gathered into the group named "joints3D" (or "joints2D" in 2D situation).
6393  * The flat element of the multiple junctions between the simple junction are stored in a group named "jointsMultiples".
6394  * \param theDomains - list of groups of volumes
6395  * \param createJointElems - if TRUE, create the elements
6396  * \param onAllBoundaries - if TRUE, the nodes and elements are also created on
6397  *        the boundary between \a theDomains and the rest mesh
6398  * \return TRUE if operation has been completed successfully, FALSE otherwise
6399  */
6400 //================================================================================
6401
6402 CORBA::Boolean
6403 SMESH_MeshEditor_i::DoubleNodesOnGroupBoundaries( const SMESH::ListOfGroups& theDomains,
6404                                                   CORBA::Boolean             createJointElems,
6405                                                   CORBA::Boolean             onAllBoundaries )
6406   throw (SALOME::SALOME_Exception)
6407 {
6408   bool isOK = false;
6409
6410   SMESH_TRY;
6411   initData();
6412
6413   SMESHDS_Mesh* aMeshDS = getMeshDS();
6414
6415   // MESSAGE("theDomains.length = "<<theDomains.length());
6416   if ( theDomains.length() <= 1 && !onAllBoundaries )
6417     THROW_SALOME_CORBA_EXCEPTION("At least 2 groups are required.", SALOME::BAD_PARAM);
6418
6419   vector<TIDSortedElemSet> domains;
6420   domains.resize( theDomains.length() );
6421
6422   for ( int i = 0, n = theDomains.length(); i < n; i++ )
6423   {
6424     SMESH::SMESH_GroupBase_var aGrp = theDomains[ i ];
6425     if ( !CORBA::is_nil( aGrp ) /*&& ( aGrp->GetType() != SMESH::NODE )*/ )
6426     {
6427 //      if ( aGrp->GetType() != SMESH::VOLUME )
6428 //        THROW_SALOME_CORBA_EXCEPTION("Not a volume group", SALOME::BAD_PARAM);
6429       SMESH::long_array_var anIDs = aGrp->GetIDs();
6430       arrayToSet( anIDs, aMeshDS, domains[ i ], SMDSAbs_All );
6431     }
6432   }
6433
6434   isOK = getEditor().DoubleNodesOnGroupBoundaries( domains, createJointElems, onAllBoundaries );
6435   // TODO publish the groups of flat elements in study
6436
6437   declareMeshModified( /*isReComputeSafe=*/ !isOK );
6438
6439   // Update Python script
6440   TPythonDump() << "isDone = " << this << ".DoubleNodesOnGroupBoundaries( " << &theDomains
6441                 << ", " << createJointElems << ", " << onAllBoundaries << " )";
6442
6443   SMESH_CATCH( SMESH::throwCorbaException );
6444
6445   myMesh_i->CreateGroupServants(); // publish created groups if any
6446
6447   return isOK;
6448 }
6449
6450 //================================================================================
6451 /*!
6452  * \brief Double nodes on some external faces and create flat elements.
6453  * Flat elements are mainly used by some types of mechanic calculations.
6454  *
6455  * Each group of the list must be constituted of faces.
6456  * Triangles are transformed in prisms, and quadrangles in hexahedrons.
6457  * @param theGroupsOfFaces - list of groups of faces
6458  * @return TRUE if operation has been completed successfully, FALSE otherwise
6459  */
6460 //================================================================================
6461
6462 CORBA::Boolean
6463 SMESH_MeshEditor_i::CreateFlatElementsOnFacesGroups( const SMESH::ListOfGroups& theGroupsOfFaces )
6464   throw (SALOME::SALOME_Exception)
6465 {
6466   SMESH_TRY;
6467   initData();
6468
6469   SMESHDS_Mesh* aMeshDS = getMeshDS();
6470
6471   vector<TIDSortedElemSet> faceGroups;
6472   faceGroups.clear();
6473
6474   for ( int i = 0, n = theGroupsOfFaces.length(); i < n; i++ )
6475   {
6476     SMESH::SMESH_GroupBase_var aGrp = theGroupsOfFaces[ i ];
6477     if ( !CORBA::is_nil( aGrp ) && ( aGrp->GetType() != SMESH::NODE ) )
6478     {
6479       TIDSortedElemSet faceGroup;
6480       faceGroup.clear();
6481       faceGroups.push_back(faceGroup);
6482       SMESH::long_array_var anIDs = aGrp->GetIDs();
6483       arrayToSet( anIDs, aMeshDS, faceGroups[ i ], SMDSAbs_All );
6484     }
6485   }
6486
6487   bool aResult = getEditor().CreateFlatElementsOnFacesGroups( faceGroups );
6488   // TODO publish the groups of flat elements in study
6489
6490   declareMeshModified( /*isReComputeSafe=*/ !aResult );
6491
6492   // Update Python script
6493   TPythonDump() << this << ".CreateFlatElementsOnFacesGroups( " << &theGroupsOfFaces << " )";
6494   return aResult;
6495
6496   SMESH_CATCH( SMESH::throwCorbaException );
6497   return false;
6498 }
6499
6500 //================================================================================
6501 /*!
6502  *  \brief Identify all the elements around a geom shape, get the faces delimiting
6503  *         the hole.
6504  *
6505  *  Build groups of volume to remove, groups of faces to replace on the skin of the
6506  *  object, groups of faces to remove inside the object, (idem edges).
6507  *  Build ordered list of nodes at the border of each group of faces to replace
6508  *  (to be used to build a geom subshape).
6509  */
6510 //================================================================================
6511
6512 void SMESH_MeshEditor_i::CreateHoleSkin(CORBA::Double                  radius,
6513                                         GEOM::GEOM_Object_ptr          theShape,
6514                                         const char*                    groupName,
6515                                         const SMESH::double_array&     theNodesCoords,
6516                                         SMESH::array_of_long_array_out GroupsOfNodes)
6517   throw (SALOME::SALOME_Exception)
6518 {
6519   SMESH_TRY;
6520
6521   initData();
6522   std::vector<std::vector<int> > aListOfListOfNodes;
6523   ::SMESH_MeshEditor aMeshEditor( myMesh );
6524
6525   theSearchersDeleter.Set( myMesh ); // remove theNodeSearcher if mesh is other
6526   if ( !theNodeSearcher )
6527     theNodeSearcher = SMESH_MeshAlgos::GetNodeSearcher( *getMeshDS() );
6528
6529   vector<double> nodesCoords;
6530   for ( CORBA::ULong i = 0; i < theNodesCoords.length(); i++)
6531   {
6532     nodesCoords.push_back( theNodesCoords[i] );
6533   }
6534
6535   TopoDS_Shape aShape = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape( theShape );
6536   aMeshEditor.CreateHoleSkin(radius, aShape, theNodeSearcher, groupName,
6537                              nodesCoords, aListOfListOfNodes);
6538
6539   GroupsOfNodes = new SMESH::array_of_long_array;
6540   GroupsOfNodes->length( aListOfListOfNodes.size() );
6541   std::vector<std::vector<int> >::iterator llIt = aListOfListOfNodes.begin();
6542   for ( CORBA::Long i = 0; llIt != aListOfListOfNodes.end(); llIt++, i++ )
6543   {
6544     vector<int>& aListOfNodes = *llIt;
6545     vector<int>::iterator lIt = aListOfNodes.begin();;
6546     SMESH::long_array& aGroup = (*GroupsOfNodes)[ i ];
6547     aGroup.length( aListOfNodes.size() );
6548     for ( int j = 0; lIt != aListOfNodes.end(); lIt++, j++ )
6549       aGroup[ j ] = (*lIt);
6550   }
6551   TPythonDump() << "lists_nodes = " << this << ".CreateHoleSkin( "
6552                 << radius << ", "
6553                 << theShape
6554                 << ", '" << groupName << "', "
6555                 << theNodesCoords << " )";
6556
6557   SMESH_CATCH( SMESH::throwCorbaException );
6558 }
6559
6560 // issue 20749 ===================================================================
6561 /*!
6562  * \brief Creates missing boundary elements
6563  *  \param elements - elements whose boundary is to be checked
6564  *  \param dimension - defines type of boundary elements to create
6565  *  \param groupName - a name of group to store created boundary elements in,
6566  *                     "" means not to create the group
6567  *  \param meshName - a name of new mesh to store created boundary elements in,
6568  *                     "" means not to create the new mesh
6569  *  \param toCopyElements - if true, the checked elements will be copied into the new mesh
6570  *  \param toCopyExistingBondary - if true, not only new but also pre-existing
6571  *                                boundary elements will be copied into the new mesh
6572  *  \param group - returns the create group, if any
6573  *  \retval SMESH::SMESH_Mesh - the mesh where elements were added to
6574  */
6575 // ================================================================================
6576
6577 SMESH::SMESH_Mesh_ptr
6578 SMESH_MeshEditor_i::MakeBoundaryMesh(SMESH::SMESH_IDSource_ptr idSource,
6579                                      SMESH::Bnd_Dimension      dim,
6580                                      const char*               groupName,
6581                                      const char*               meshName,
6582                                      CORBA::Boolean            toCopyElements,
6583                                      CORBA::Boolean            toCopyExistingBondary,
6584                                      SMESH::SMESH_Group_out    group)
6585   throw (SALOME::SALOME_Exception)
6586 {
6587   SMESH_TRY;
6588   initData();
6589
6590   if ( dim > SMESH::BND_1DFROM2D )
6591     THROW_SALOME_CORBA_EXCEPTION("Invalid boundary dimension", SALOME::BAD_PARAM);
6592
6593   SMESHDS_Mesh* aMeshDS = getMeshDS();
6594
6595   SMESH::SMESH_Mesh_var mesh_var;
6596   SMESH::SMESH_Group_var group_var;
6597
6598   TPythonDump pyDump;
6599
6600   TIDSortedElemSet elements;
6601   SMDSAbs_ElementType elemType = (dim == SMESH::BND_1DFROM2D) ? SMDSAbs_Face : SMDSAbs_Volume;
6602   if ( idSourceToSet( idSource, aMeshDS, elements, elemType,/*emptyIfIsMesh=*/true ))
6603   {
6604     // mesh to fill in
6605     mesh_var =
6606       strlen(meshName) ? makeMesh(meshName) : SMESH::SMESH_Mesh::_duplicate(myMesh_i->_this());
6607     SMESH_Mesh_i* mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh_var );
6608     // other mesh
6609     SMESH_Mesh* smesh_mesh = (mesh_i==myMesh_i) ? (SMESH_Mesh*)0 : &mesh_i->GetImpl();
6610
6611     // group of new boundary elements
6612     SMESH_Group* smesh_group = 0;
6613     if ( strlen(groupName) )
6614     {
6615       group_var = mesh_i->CreateGroup( SMESH::ElementType(int(elemType)-1),groupName);
6616       if ( SMESH_GroupBase_i* group_i = SMESH::DownCast<SMESH_GroupBase_i*>( group_var ))
6617         smesh_group = group_i->GetSmeshGroup();
6618     }
6619
6620     // do it
6621     getEditor().MakeBoundaryMesh( elements,
6622                                   ::SMESH_MeshEditor::Bnd_Dimension(dim),
6623                                   smesh_group,
6624                                   smesh_mesh,
6625                                   toCopyElements,
6626                                   toCopyExistingBondary);
6627
6628     if ( smesh_mesh )
6629       smesh_mesh->GetMeshDS()->Modified();
6630   }
6631
6632   const char* dimName[] = { "BND_2DFROM3D", "BND_1DFROM3D", "BND_1DFROM2D" };
6633
6634   // result of MakeBoundaryMesh() is a tuple (mesh, group)
6635   if ( mesh_var->_is_nil() )
6636     pyDump << myMesh_i->_this() << ", ";
6637   else
6638     pyDump << mesh_var << ", ";
6639   if ( group_var->_is_nil() )
6640     pyDump << "_NoneGroup = "; // assignment to None is forbidden
6641   else
6642     pyDump << group_var << " = ";
6643   pyDump << this << ".MakeBoundaryMesh( "
6644          << idSource << ", "
6645          << "SMESH." << dimName[int(dim)] << ", "
6646          << "'" << groupName << "', "
6647          << "'" << meshName<< "', "
6648          << toCopyElements << ", "
6649          << toCopyExistingBondary << ")";
6650
6651   group = group_var._retn();
6652   return mesh_var._retn();
6653
6654   SMESH_CATCH( SMESH::throwCorbaException );
6655   return SMESH::SMESH_Mesh::_nil();
6656 }
6657
6658 //================================================================================
6659 /*!
6660  * \brief Creates missing boundary elements
6661  *  \param dimension - defines type of boundary elements to create
6662  *  \param groupName - a name of group to store all boundary elements in,
6663  *    "" means not to create the group
6664  *  \param meshName - a name of a new mesh, which is a copy of the initial 
6665  *    mesh + created boundary elements; "" means not to create the new mesh
6666  *  \param toCopyAll - if true, the whole initial mesh will be copied into
6667  *    the new mesh else only boundary elements will be copied into the new mesh
6668  *  \param groups - optional groups of elements to make boundary around
6669  *  \param mesh - returns the mesh where elements were added to
6670  *  \param group - returns the created group, if any
6671  *  \retval long - number of added boundary elements
6672  */
6673 //================================================================================
6674
6675 CORBA::Long SMESH_MeshEditor_i::MakeBoundaryElements(SMESH::Bnd_Dimension dim,
6676                                                      const char* groupName,
6677                                                      const char* meshName,
6678                                                      CORBA::Boolean toCopyAll,
6679                                                      const SMESH::ListOfIDSources& groups,
6680                                                      SMESH::SMESH_Mesh_out mesh,
6681                                                      SMESH::SMESH_Group_out group)
6682   throw (SALOME::SALOME_Exception)
6683 {
6684   SMESH_TRY;
6685   initData();
6686
6687   if ( dim > SMESH::BND_1DFROM2D )
6688     THROW_SALOME_CORBA_EXCEPTION("Invalid boundary dimension", SALOME::BAD_PARAM);
6689
6690   // separate groups belonging to this and other mesh
6691   SMESH::ListOfIDSources_var groupsOfThisMesh  = new SMESH::ListOfIDSources;
6692   SMESH::ListOfIDSources_var groupsOfOtherMesh = new SMESH::ListOfIDSources;
6693   groupsOfThisMesh ->length( groups.length() );
6694   groupsOfOtherMesh->length( groups.length() );
6695   int nbGroups = 0, nbGroupsOfOtherMesh = 0;
6696   for ( CORBA::ULong i = 0; i < groups.length(); ++i )
6697   {
6698     SMESH::SMESH_Mesh_var m = groups[i]->GetMesh();
6699     if ( myMesh_i != SMESH::DownCast<SMESH_Mesh_i*>( m ))
6700       groupsOfOtherMesh[ nbGroupsOfOtherMesh++ ] = groups[i];
6701     else
6702       groupsOfThisMesh[ nbGroups++ ] = groups[i];
6703     if ( SMESH::DownCast<SMESH_Mesh_i*>( groups[i] ))
6704       THROW_SALOME_CORBA_EXCEPTION("expected a group but received a mesh", SALOME::BAD_PARAM);
6705   }
6706   groupsOfThisMesh->length( nbGroups );
6707   groupsOfOtherMesh->length( nbGroupsOfOtherMesh );
6708
6709   int nbAdded = 0;
6710   TPythonDump pyDump;
6711
6712   if ( nbGroupsOfOtherMesh > 0 )
6713   {
6714     // process groups belonging to another mesh
6715     SMESH::SMESH_Mesh_var    otherMesh = groupsOfOtherMesh[0]->GetMesh();
6716     SMESH::SMESH_MeshEditor_var editor = otherMesh->GetMeshEditor();
6717     nbAdded += editor->MakeBoundaryElements( dim, groupName, meshName, toCopyAll,
6718                                              groupsOfOtherMesh, mesh, group );
6719   }
6720
6721   SMESH::SMESH_Mesh_var mesh_var;
6722   SMESH::SMESH_Group_var group_var;
6723
6724   // get mesh to fill
6725   mesh_var = SMESH::SMESH_Mesh::_duplicate( myMesh_i->_this() );
6726   const bool toCopyMesh = ( strlen( meshName ) > 0 );
6727   if ( toCopyMesh )
6728   {
6729     if ( toCopyAll )
6730       mesh_var = SMESH_Gen_i::GetSMESHGen()->CopyMesh(mesh_var,
6731                                                       meshName,
6732                                                       /*toCopyGroups=*/false,
6733                                                       /*toKeepIDs=*/true);
6734     else
6735       mesh_var = makeMesh(meshName);
6736   }
6737   SMESH_Mesh_i* mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh_var );
6738   SMESH_Mesh*  tgtMesh = &mesh_i->GetImpl();
6739
6740   // source mesh
6741   SMESH_Mesh*     srcMesh = ( toCopyMesh && !toCopyAll ) ? myMesh : tgtMesh;
6742   SMESHDS_Mesh* srcMeshDS = srcMesh->GetMeshDS();
6743
6744   // group of boundary elements
6745   SMESH_Group* smesh_group = 0;
6746   SMDSAbs_ElementType elemType = (dim == SMESH::BND_2DFROM3D) ? SMDSAbs_Volume : SMDSAbs_Face;
6747   if ( strlen(groupName) )
6748   {
6749     SMESH::ElementType groupType = SMESH::ElementType( int(elemType)-1 );
6750     group_var = mesh_i->CreateGroup( groupType, groupName );
6751     if ( SMESH_GroupBase_i* group_i = SMESH::DownCast<SMESH_GroupBase_i*>( group_var ))
6752       smesh_group = group_i->GetSmeshGroup();
6753   }
6754
6755   TIDSortedElemSet elements;
6756
6757   if ( groups.length() > 0 )
6758   {
6759     for ( int i = 0; i < nbGroups; ++i )
6760     {
6761       elements.clear();
6762       if ( idSourceToSet( groupsOfThisMesh[i], srcMeshDS, elements, elemType,/*emptyIfIsMesh=*/0 ))
6763       {
6764         SMESH::Bnd_Dimension bdim = 
6765           ( elemType == SMDSAbs_Volume ) ? SMESH::BND_2DFROM3D : SMESH::BND_1DFROM2D;
6766         nbAdded += getEditor().MakeBoundaryMesh( elements,
6767                                                  ::SMESH_MeshEditor::Bnd_Dimension(bdim),
6768                                                  smesh_group,
6769                                                  tgtMesh,
6770                                                  /*toCopyElements=*/false,
6771                                                  /*toCopyExistingBondary=*/srcMesh != tgtMesh,
6772                                                  /*toAddExistingBondary=*/true,
6773                                                  /*aroundElements=*/true);
6774       }
6775     }
6776   }
6777   else
6778   {
6779     nbAdded += getEditor().MakeBoundaryMesh( elements,
6780                                              ::SMESH_MeshEditor::Bnd_Dimension(dim),
6781                                              smesh_group,
6782                                              tgtMesh,
6783                                              /*toCopyElements=*/false,
6784                                              /*toCopyExistingBondary=*/srcMesh != tgtMesh,
6785                                              /*toAddExistingBondary=*/true);
6786   }
6787   tgtMesh->GetMeshDS()->Modified();
6788
6789   const char* dimName[] = { "BND_2DFROM3D", "BND_1DFROM3D", "BND_1DFROM2D" };
6790
6791   // result of MakeBoundaryElements() is a tuple (nb, mesh, group)
6792   pyDump << "nbAdded, ";
6793   if ( mesh_var->_is_nil() )
6794     pyDump << myMesh_i->_this() << ", ";
6795   else
6796     pyDump << mesh_var << ", ";
6797   if ( group_var->_is_nil() )
6798     pyDump << "_NoneGroup = "; // assignment to None is forbidden
6799   else
6800     pyDump << group_var << " = ";
6801   pyDump << this << ".MakeBoundaryElements( "
6802          << "SMESH." << dimName[int(dim)] << ", "
6803          << "'" << groupName << "', "
6804          << "'" << meshName<< "', "
6805          << toCopyAll << ", "
6806          << groups << ")";
6807
6808   mesh  = mesh_var._retn();
6809   group = group_var._retn();
6810   return nbAdded;
6811
6812   SMESH_CATCH( SMESH::throwCorbaException );
6813   return 0;
6814 }